В основе прогресс-баров и индикаторов загрузки на базе Lottie Web
лежит идея синхронизации состояния загрузки с временной шкалой анимации.
Каждая Lottie-анимация представляет собой дискретную последовательность
кадров, где ключевыми параметрами выступают currentFrame и
totalFrames. Их отношение формирует нормализованное
значение прогресса:
progress = currentFrame / totalFramesЭто значение используется как универсальный мост между логикой загрузки и визуальным отображением состояния интерфейса.
Объект анимации, создаваемый через lottie.loadAnimation,
предоставляет доступ к внутреннему состоянию проигрывания:
animationItem.currentFrame — текущий кадрanimationItem.totalFrames — общее количество
кадровanimationItem.playDirection — направление
воспроизведенияanimationItem.isPaused — состояние паузыПрогресс становится вычисляемой величиной, которая обновляется на каждом кадре через события рендера.
Основным механизмом синхронизации выступает событие
enterFrame. Оно вызывается на каждом шаге анимационного
цикла и позволяет привязать внешнюю логику к текущему состоянию
проигрывания.
const animation = lottie.loadAnimation({
container: document.getElementById('loader'),
renderer: 'svg',
loop: false,
autoplay: true,
path: 'loader.json'
});
animation.addEventListener('enterFrame', (e) => {
const progress = e.currentTime / animation.totalFrames;
updateProgressBar(progress);
});
Значение e.currentTime отражает текущий кадр в момент
события, что позволяет избежать прямого обращения к внутреннему
состоянию объекта.
Линейная модель прогресса строится на прямом отображении отношения кадров к общей длине анимации. Такой подход применяется при необходимости визуально синхронизировать загрузку данных и анимацию.
function updateProgressBar(progress) {
const bar = document.querySelector('.progress-bar');
bar.style.transform = `scaleX(${progress})`;
}
CSS-реализация часто использует transform: scaleX, что
минимизирует перерасчёт layout и обеспечивает стабильную
производительность.
Интеграция Lottie с процессом загрузки данных строится через сопоставление прогресса сети и кадров анимации.
function loadWithProgress(url) {
const animation = lottie.loadAnimation({
container: document.getElementById('loader'),
renderer: 'svg',
loop: false,
autoplay: false,
path: 'loader.json'
});
fetch(url).then(response => {
const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let received = 0;
function read() {
return reader.read().then(({ done, value }) => {
if (done) return;
received += value.length;
const networkProgress = received / contentLength;
const frame = networkProgress * animation.totalFrames;
animation.goToAndStop(frame, true);
return read();
});
}
return read();
});
}
Механизм goToAndStop используется для жесткой привязки
анимационного кадра к внешнему прогрессу, что позволяет полностью
контролировать визуальное состояние.
В случаях, когда точный прогресс неизвестен, используется циклическое воспроизведение части анимации. Такой режим реализуется через бесконечный loop и ограниченные сегменты кадров.
const animation = lottie.loadAnimation({
container: document.getElementById('loader'),
renderer: 'svg',
loop: true,
autoplay: true,
path: 'loader.json'
});
Для создания ощущения движения без реального прогресса часто применяются циклы с коротким сегментом:
animation.playSegments([0, 30], true);
Это формирует визуальный эффект непрерывного движения при отсутствии данных о загрузке.
Сегменты позволяют разбивать анимацию на логические части, каждая из которых соответствует этапу процесса.
Пример использования сегментов:
animation.playSegments([0, 20], true);
fetchData().then(() => {
animation.playSegments([20, 60], true);
return finalize();
}).then(() => {
animation.playSegments([60, 100], true);
});
Сегментный подход обеспечивает точное визуальное отражение этапов системы.
Контроль временной оси осуществляется через изменение скорости воспроизведения:
animation.setSpeed(0.5);
Замедление используется при необходимости растянуть визуальное восприятие загрузки, особенно если сетевые операции происходят неравномерно.
Дополнительно применяется принудительная остановка:
animation.pause();
animation.goToAndStop(0, true);
Вместо кадрового подхода используется нормализация в диапазон
[0, 1], где 0 — начало, 1 — завершение.
function setProgress(animation, value) {
const frame = value * animation.totalFrames;
animation.goToAndStop(frame, true);
}
Такая модель удобна при интеграции с системами управления состоянием (state management), где прогресс уже вычислен как доля.
Асинхронные операции становятся источником прогресса, который напрямую транслируется в анимацию.
async function process() {
const animation = lottie.loadAnimation({
container: document.getElementById('loader'),
renderer: 'svg',
loop: false,
autoplay: false,
path: 'loader.json'
});
const steps = [taskA, taskB, taskC];
for (let i = 0; i < steps.length; i++) {
await steps[i]();
const progress = (i + 1) / steps.length;
animation.goToAndStop(progress * animation.totalFrames, true);
}
}
Такой подход обеспечивает дискретную визуализацию прогресса сложных процессов.
После достижения 100% часто применяется обратное проигрывание для плавного исчезновения индикатора.
animation.setDirection(-1);
animation.play();
Обратное направление позволяет избежать резких переходов интерфейса.
При высокой частоте обновления прогресса критично минимизировать DOM-операции. SVG-рендеринг Lottie требует аккуратного управления перерисовками.
Рекомендуемые принципы:
querySelector внутри цикловrequestAnimationFrame для
синхронизацииlet lastUpdate = 0;
function throttledUpdate(progress) {
const now = performance.now();
if (now - lastUpdate < 16) return;
lastUpdate = now;
animation.goToAndStop(progress * animation.totalFrames, true);
}
Часто используется комбинация Lottie-анимации и классического прогресс-бара. В этом случае Lottie отвечает за декоративную часть, а числовой прогресс — за точность.
function sync(progress) {
animation.goToAndStop(progress * animation.totalFrames, true);
document.querySelector('.percent').textContent = `${Math.round(progress * 100)}%`;
}
Такая модель разделяет визуальную и функциональную составляющие интерфейса.
Некоторые интерфейсы используют обратную шкалу, где анимация убывает по мере загрузки.
const frame = (1 - progress) * animation.totalFrames;
animation.goToAndStop(frame, true);
Это применяется в сценариях, где индикатор представляет процесс освобождения ресурсов или завершения операции.
Lottie Web поддерживает несколько рендереров: SVG, Canvas и HTML. Поведение прогресс-баров зависит от выбранного режима:
При частых обновлениях прогресса Canvas-режим снижает нагрузку на DOM и повышает стабильность анимации.
После достижения финального состояния анимация фиксируется на последнем кадре:
animation.goToAndStop(animation.totalFrames, true);
animation.pause();
Фиксация состояния предотвращает случайные циклы перезапуска и обеспечивает стабильное отображение завершённого индикатора.