Lottie-анимации представляют собой JSON-описание сцен, в которых
отдельные элементы часто выносятся во внешние ресурсы: изображения,
шрифты, иногда дополнительные JSON-фрагменты. Основной механизм
связывания таких ресурсов основан на поле assets, где
каждый элемент описывает тип ресурса и способ его загрузки.
{
"assets": [
{
"id": "image_0",
"w": 512,
"h": 512,
"u": "images/",
"p": "img_0.png",
"e": 0
}
]
}
Ключевые поля:
Система загрузки изображений в Lottie Web опирается на конкатенацию
u + p, формируя итоговый URL.
При использовании lottie-web основной точкой входа
является функция lottie.loadAnimation, где задаётся путь к
JSON или передаются данные напрямую.
import lottie from 'lottie-web';
lottie.loadAnimation({
container: document.getElementById('animation'),
renderer: 'svg',
loop: true,
autoplay: true,
path: '/animations/data.json'
});
При таком подходе все относительные пути внутри JSON интерпретируются относительно расположения самого JSON-файла. Это поведение становится критическим при переносе файлов между средами.
Механизм разрешения ресурсов зависит от того, как заданы
u и как загружается основной JSON.
Если JSON расположен по адресу:
/animations/hero/data.json
а внутри него:
"u": "images/",
"p": "img_1.png"
итоговый путь становится:
/animations/hero/images/img_1.png
Это поведение фиксируется браузером и зависит от URL JSON-документа.
При использовании CDN или отдельного домена требуется явное указание абсолютного пути:
"u": "https://cdn.example.com/lottie/hero/images/"
Такой подход устраняет зависимость от структуры хоста, но увеличивает связность с инфраструктурой доставки.
В некоторых сборках и обёртках над Lottie Web применяется параметризация пути на уровне конфигурации. Наиболее распространённый подход — модификация JSON перед передачей в движок.
fetch('/animations/data.json')
.then(res => res.json())
.then(animationData => {
const basePath = 'https://cdn.example.com/hero/';
animationData.assets.forEach(asset => {
if (asset.u) {
asset.u = basePath + asset.u;
}
});
lottie.loadAnimation({
container: document.getElementById('animation'),
renderer: 'svg',
loop: true,
autoplay: true,
animationData
});
});
Такой способ применяется при необходимости динамического переключения окружений: dev, staging, production.
При использовании обёрток или кастомных сборщиков часто вводится
концепция assetsDir — централизованного префикса для всех
ресурсов.
const assetsDir = '/static/lottie/hero/';
lottie.loadAnimation({
container: document.getElementById('animation'),
renderer: 'svg',
loop: true,
autoplay: true,
path: assetsDir + 'data.json'
});
В этом случае важно согласовать:
u внутри JSONНесоответствие одного элемента приводит к разрыву цепочки загрузки.
В некоторых анимациях изображения помечаются как внешние
("e": 1). В таком случае Lottie Web не пытается искать их в
локальной структуре и ожидает, что они доступны по прямому URL.
{
"id": "image_2",
"p": "https://cdn.example.com/img/logo.png",
"e": 1
}
Поведение загрузчика:
up<img> или SVG
<image>Это применяется для интеграции с внешними CDN и динамическими медиа-хранилищами.
В случаях, когда требуется полный контроль над загрузкой ресурсов, применяется предварительная подгрузка изображений с последующей подстановкой base64.
function toBase64(url) {
return fetch(url)
.then(res => res.blob())
.then(blob => new Promise(resolve => {
const reader = new FileReader();
reader.onload end = () => resolve(reader.result);
reader.readAsDataURL(blob);
}));
}
fetch('/animations/data.json')
.then(res => res.json())
.then(async (animationData) => {
for (const asset of animationData.assets) {
if (asset.p && asset.e !== 1) {
const fullUrl = asset.u + asset.p;
asset.p = await toBase64(fullUrl);
asset.u = '';
}
}
lottie.loadAnimation({
container: document.getElementById('animation'),
renderer: 'svg',
animationData
});
});
Такой подход исключает сетевые зависимости во время воспроизведения.
При размещении анимаций на CDN структура обычно разделяется:
/cdn/lottie/
hero/
data.json
images/
img_0.png
img_1.png
Критический момент — синхронизация путей внутри JSON с реальной структурой CDN. При переносе между средами часто применяется автоматическая пост-обработка JSON:
u на CDN prefixЗагрузка ресурсов Lottie Web подчиняется правилам CORS, поскольку изображения и JSON запрашиваются через браузерные API.
Типовые сценарии ошибок:
Access-Control-Allow-Origin<image> при внешних
источникахКорректная конфигурация сервера требует:
Access-Control-Allow-Origin: *
или ограниченного домена:
Access-Control-Allow-Origin: https://app.example.com
В некоторых реализациях требуется перехват запросов ресурсов. Это достигается через модификацию JSON перед инициализацией или через сервисные прокси.
const assetMap = new Map([
['img_0.png', '/optimized/img_0.webp'],
['img_1.png', '/optimized/img_1.webp']
]);
fetch('/animations/data.json')
.then(res => res.json())
.then(animationData => {
animationData.assets.forEach(asset => {
const fileName = asset.p;
if (assetMap.has(fileName)) {
asset.p = assetMap.get(fileName);
asset.u = '';
}
});
lottie.loadAnimation({
container: document.getElementById('animation'),
renderer: 'svg',
animationData
});
});
Такой слой абстракции позволяет:
Нарушение загрузки ресурсов чаще всего связано с:
u (отсутствие завершающего
/)Пример проблемного значения:
"u": "images"
"p": "img.png"
Результат:
imagesimg.png
Корректный вариант:
"u": "images/",
"p": "img.png"
Для разделения dev/staging/prod используется вычисление базового URL:
const env = {
dev: 'http://localhost:3000/assets/',
stage: 'https://stage-cdn.example.com/lottie/',
prod: 'https://cdn.example.com/lottie/'
};
const base = env[process.env.NODE_ENV];
fetch(base + 'hero/data.json')
.then(res => res.json())
.then(animationData => {
animationData.assets.forEach(asset => {
if (asset.u) {
asset.u = base + asset.u;
}
});
lottie.loadAnimation({
container: document.getElementById('animation'),
renderer: 'svg',
animationData
});
});
Такой подход обеспечивает независимость сборки от структуры файловой системы.
Ошибочная организация ресурсов приводит к:
Оптимальная стратегия:
uПри использовании renderer: 'svg' изображения
вставляются как элементы <image> внутри SVG-дерева.
Это накладывает дополнительные ограничения:
В отличие от canvas-рендерера, SVG требует полного доступа к ресурсам на момент вставки узла в DOM.
Для стабильного поведения анимаций применяется версионирование путей:
"u": "images/v12/",
"p": "img_0.png"
или через query string:
img_0.png?v=12
Это предотвращает использование устаревших изображений при обновлении дизайна анимации.