Масштабирование анимации под контейнер

Lottie Web рендерит анимации либо в SVG, либо в Canvas, либо в HTML, и в каждом режиме логика масштабирования привязана к контейнеру, в который вставляется анимация. Базовый принцип работы заключается в том, что размеры анимации не задаются внутри JSON как фиксированная геометрия для отображения, а вычисляются относительно размеров DOM-элемента, переданного в container.

const animation = lottie.loadAnimation({
  container: document.querySelector('.animation'),
  renderer: 'svg',
  loop: true,
  autoplay: true,
  path: 'animation.json'
});

В этом случае контейнер становится единственным источником размеров. Любое изменение ширины или высоты DOM-элемента требует синхронного пересчёта рендера.

Ключевое поведение:

  • SVG масштабируется через viewBox
  • Canvas пересчитывает пиксельную плотность
  • HTML-рендер перестраивает DOM-структуру

Базовая модель масштабирования

В основе Lottie лежит концепция исходного размера композиции, заданного в After Effects. Эти размеры сохраняются в JSON как w и h:

{
  "w": 800,
  "h": 600
}

При рендере Lottie сопоставляет:

  • исходное разрешение композиции
  • текущие размеры контейнера

И вычисляет коэффициент масштабирования:

scaleX = containerWidth / animationWidth
scaleY = containerHeight / animationHeight

В SVG-режиме это выражается через viewBox и трансформации групп, в Canvas — через матрицу преобразования контекста.

Растяжение и сохранение пропорций

Поведение масштабирования зависит от настройки rendererSettings, а также от внутреннего режима SVG.

На уровне SVG ключевую роль играет атрибут:

preserveAspectRatio="xMidYMid meet"

Lottie использует аналогичную модель:

  • meet — полное сохранение пропорций
  • slice — заполнение контейнера с обрезкой
  • растяжение (non-uniform scaling) — редко используется, но возможно через кастомные трансформации

В JavaScript API явного параметра preserveAspectRatio нет, но поведение можно косвенно контролировать через CSS и размеры контейнера.

CSS-основа адаптивного масштабирования

Наиболее стабильный способ масштабирования Lottie-анимаций — управление контейнером через CSS:

.animation {
  width: 100%;
  height: 100%;
}

или в адаптивных макетах:

.animation {
  width: 50vw;
  height: 50vh;
}

SVG внутри контейнера автоматически подстраивается, поскольку Lottie задаёт width: 100%; height: 100% на внутренний SVG-элемент.

Важно, что отсутствие явной высоты у контейнера приводит к нулевой геометрии, что полностью ломает рендер.

Пересчёт размеров при изменении контейнера

Lottie Web не всегда автоматически реагирует на изменение размеров DOM-элемента. В ряде случаев требуется принудительный пересчёт:

window.addEventListener('resize', () => {
  animation.resize();
});

Метод resize() инициирует:

  • пересчёт размеров canvas/svg
  • обновление матриц трансформации
  • перерасчёт плотности пикселей (для canvas)

При частых изменениях размеров использование resize без оптимизации приводит к избыточным перерасчётам, поэтому применяется троттлинг:

let timeout;

window.addEventListener('resize', () => {
  clearTimeout(timeout);
  timeout = setTimeout(() => {
    animation.resize();
  }, 100);
});

ResizeObserver как современный механизм

Более точный способ отслеживания контейнера — ResizeObserver, который реагирует не на окно, а на конкретный элемент:

const container = document.querySelector('.animation');

const observer = new ResizeObserver(() => {
  animation.resize();
});

observer.observe(container);

Этот подход критически важен в интерфейсах, где контейнер меняет размеры независимо от окна:

  • sidebars
  • flex/grid лейауты
  • модальные окна
  • динамические панели

Поведение SVG при масштабировании

SVG-рендер Lottie использует внутреннюю систему групп <g> с трансформациями:

  • корневой слой получает scale transform
  • все слои композиции наследуют трансформацию
  • координатная система остаётся в исходных единицах After Effects

Это означает, что:

  • не происходит пересчёта path-данных
  • масштабирование всегда математическое, а не геометрическое
  • качество изображения не деградирует

Особенность: при резких изменениях размера возможны микросмещения из-за субпиксельного округления.

Canvas-рендер и плотность пикселей

При использовании Canvas (renderer: 'canvas') масштабирование включает пересчёт devicePixelRatio:

const animation = lottie.loadAnimation({
  container: document.querySelector('.animation'),
  renderer: 'canvas',
  loop: true,
  autoplay: true,
  path: 'animation.json',
  rendererSettings: {
    clearCanvas: true,
    progressiveLoad: false
  }
});

Canvas-режим:

  • пересоздаёт буфер при resize
  • учитывает window.devicePixelRatio
  • может терять резкость при неправильной настройке контейнера

Корректная стратегия — всегда задавать размеры через CSS, а не через атрибуты canvas вручную.

Контроль масштабирования через transform контейнера

Альтернативный подход — не менять размер контейнера, а масштабировать его через CSS transform:

.animation-wrapper {
  transform: scale(1.5);
  transform-origin: center;
}

В этом случае:

  • Lottie считает контейнер фиксированным
  • масштабирование происходит на уровне GPU
  • отсутствует пересчёт геометрии SVG

Преимущество — высокая производительность при анимациях интерфейса.

Недостаток — возможное размывание при Canvas-рендере.

Гибридные схемы масштабирования

В сложных интерфейсах используется комбинированный подход:

  • контейнер фиксируется через flex/grid
  • Lottie масштабируется через resize()
  • дополнительно применяется max-width / max-height
.animation {
  width: 100%;
  max-width: 600px;
  aspect-ratio: 4 / 3;
}

Такой подход обеспечивает:

  • стабильную пропорцию
  • предсказуемую геометрию
  • отсутствие скачков при перерасчётах layout

Масштабирование с сохранением центра композиции

При изменении размеров контейнера важно учитывать точку привязки.

SVG-рендер использует центр композиции как базовую точку масштабирования. Если контейнер не центрирован визуально, возможны смещения.

Для стабилизации используется:

.animation {
  display: flex;
  align-items: center;
  justify-content: center;
}

Это фиксирует визуальный центр относительно контейнера и предотвращает «прыжки» при resize.

Работа с динамическими контейнерами

В интерфейсах, где контейнер изменяет размеры из-за контента, возникает необходимость постоянной синхронизации:

  • раскрывающиеся панели
  • аккордеоны
  • табы
  • динамические списки

В таких случаях ResizeObserver становится обязательным инструментом, поскольку window.resize не отражает локальные изменения.

const observer = new ResizeObserver(() => {
  animation.resize();
});

observer.observe(document.querySelector('.panel'));

Типичные проблемы масштабирования

Часто встречающиеся ошибки связаны не с Lottie, а с контейнером:

  • отсутствие высоты у родителя
  • использование position: absolute без размеров
  • flex-контейнер без min-height
  • canvas без учета devicePixelRatio
  • отсутствие вызова resize() при динамическом изменении

Каждая из этих проблем приводит к рассинхронизации между JSON-композицией и реальным DOM-рендером.

Стабильная модель адаптивного рендера

Устойчивое масштабирование достигается при соблюдении трёх условий:

  • контейнер имеет явные размеры
  • используется ResizeObserver или контролируемый resize
  • сохранены пропорции через CSS (aspect-ratio или эквивалент)

При такой конфигурации Lottie Web перестаёт зависеть от внешнего контекста и работает как предсказуемый слой в интерфейсной системе, где размер анимации всегда является производной от DOM-геометрии, а не от внутренней логики библиотеки