Учет prefers-reduced-motion

Медиа-запрос prefers-reduced-motion является частью спецификации CSS Media Queries Level 5 и предназначен для определения пользовательских настроек операционной системы, ограничивающих анимации. В контексте интерфейсов, использующих Lottie Web, этот сигнал становится ключевым механизмом адаптации анимационного поведения под требования доступности.

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


Определение пользовательского предпочтения на уровне браузера

В JavaScript доступ к системной настройке осуществляется через window.matchMedia.

const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');

Состояние можно проверить напрямую:

if (prefersReducedMotion.matches) {
  // режим уменьшенной анимации активен
}

Также возможно отслеживание изменений в рантайме:

prefersReducedMotion.addEventListener('change', (event) => {
  if (event.matches) {
    // переключение в режим reduced motion
  } else {
    // возврат к стандартной анимации
  }
});

Данный механизм особенно важен в SPA-приложениях, где состояние интерфейса изменяется без перезагрузки страницы.


Поведение Lottie Web в контексте ограничения анимации

Библиотека Lottie Web по умолчанию не учитывает системные настройки доступности. Анимация запускается согласно параметрам autoplay, loop и управлению через API lottie-web.

Типовая инициализация:

import lottie from 'lottie-web';

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

При активированном prefers-reduced-motion: reduce такое поведение становится нежелательным, поскольку анимация продолжает воспроизводиться независимо от системных предпочтений.


Стратегии адаптации Lottie-анимаций

Полное отключение анимации

Наиболее строгий подход заключается в предотвращении запуска Lottie вовсе. В этом случае интерфейс ограничивается статическим состоянием.

const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

const animation = lottie.loadAnimation({
  container: document.getElementById('animation'),
  renderer: 'svg',
  loop: prefersReducedMotion ? false : true,
  autoplay: !prefersReducedMotion,
  path: '/animations/scene.json'
});

Такой подход снижает нагрузку на визуальную систему, но может приводить к потере смысловой нагрузки, если анимация несёт информационную функцию.


Использование статического кадра вместо проигрывания

Более гибкая модель заключается в рендере первого кадра композиции. Lottie позволяет программно управлять текущим временем анимации.

const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

const animation = lottie.loadAnimation({
  container: document.getElementById('animation'),
  renderer: 'svg',
  loop: true,
  autoplay: !prefersReducedMotion,
  path: '/animations/scene.json'
});

if (prefersReducedMotion) {
  animation.addEventListener('DOMLoaded', () => {
    animation.goToAndStop(0, true);
  });
}

Метод goToAndStop(0, true) фиксирует анимацию на первом кадре, обеспечивая визуальную стабильность при сохранении графического элемента.


Замена анимации альтернативным визуальным представлением

В сложных интерфейсах применяется подмена Lottie-компонента на статичное изображение или упрощённую графику.

const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

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

if (prefersReducedMotion) {
  container.innerHTML = '<img src="/images/scene-static.svg" alt="">';
} else {
  lottie.loadAnimation({
    container,
    renderer: 'svg',
    loop: true,
    autoplay: true,
    path: '/animations/scene.json'
  });
}

Подобная схема часто используется в интерфейсах с высоким уровнем визуальной плотности, где анимация выполняет вспомогательную, а не критическую функцию.


Интеграция с жизненным циклом компонентов

В рамках компонентных архитектур (React, Vue, Svelte) контроль prefers-reduced-motion обычно выносится в уровень инициализации компонента.

Обобщённый подход включает:

  • определение состояния системы
  • выбор стратегии рендера
  • условную инициализацию Lottie
  • корректное уничтожение инстанса

Пример логики управления:

let animationInstance = null;

function initAnimation() {
  const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  if (reduced) {
    const container = document.getElementById('animation');
    container.innerHTML = '';
    return;
  }

  animationInstance = lottie.loadAnimation({
    container: document.getElementById('animation'),
    renderer: 'svg',
    loop: true,
    autoplay: true,
    path: '/animations/scene.json'
  });
}

function destroyAnimation() {
  if (animationInstance) {
    animationInstance.destroy();
    animationInstance = null;
  }
}

Обработка динамического изменения системного предпочтения

Современные операционные системы позволяют менять настройки уменьшенной анимации без перезапуска браузера. Это требует реактивного подхода.

const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');

function handleMotionPreference(event) {
  if (event.matches) {
    if (animationInstance) {
      animationInstance.pause();
    }
  } else {
    if (animationInstance) {
      animationInstance.play();
    }
  }
}

mediaQuery.addEventListener('change', handleMotionPreference);

В случае сложных анимаций предпочтительно не просто ставить на паузу, а переключать режим отображения полностью, поскольку пауза может сохранять визуально «застывшее движение», что также воспринимается как нежелательная динамика.


Взаимодействие с производительностью и энергопотреблением

Режим prefers-reduced-motion часто коррелирует с ситуациями, в которых пользователь стремится минимизировать нагрузку на устройство. Это особенно актуально для мобильных платформ.

Lottie Web в SVG-рендерере активно использует DOM-операции и может создавать значительную нагрузку при сложных композициях. Поэтому в reduced motion режиме применяются дополнительные оптимизации:

  • отключение requestAnimationFrame циклов
  • остановка интерполяции ключевых кадров
  • отказ от бесконечного loop
  • фиксирование статического кадра

Комбинация с Intersection Observer

Даже при отсутствии reduced motion, анимации часто не должны проигрываться вне видимой области экрана. Комбинирование prefers-reduced-motion с IntersectionObserver позволяет формировать адаптивную модель поведения.

const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (!animationInstance) return;

    if (prefersReduced) {
      animationInstance.goToAndStop(0, true);
      return;
    }

    if (entry.isIntersecting) {
      animationInstance.play();
    } else {
      animationInstance.pause();
    }
  });
});

Такой подход минимизирует ненужное воспроизведение и снижает нагрузку на GPU/CPU.


Архитектурный паттерн выбора режима анимации

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

Логика обычно сводится к следующим состояниям:

  • ENABLED — полная анимация
  • REDUCED_STATIC — первый кадр
  • DISABLED — отсутствие рендера

Пример абстракции:

function getMotionMode() {
  return window.matchMedia('(prefers-reduced-motion: reduce)').matches
    ? 'REDUCED_STATIC'
    : 'ENABLED';
}

Использование такого слоя позволяет унифицировать поведение всех Lottie-компонентов в приложении и исключить дублирование логики.


Ограничения и особенности поведения Lottie JSON

Некоторые Lottie-анимации содержат:

  • экспрессивные морфинг-переходы
  • частые изменения opacity и transform
  • циклические эффекты частиц

В режиме reduced motion такие композиции могут оставаться визуально «шумными» даже при остановке. В этих случаях применяется предварительная подготовка ассетов:

  • создание альтернативного статического рендера
  • экспорт отдельного «key frame poster»
  • упрощение композиции в After Effects перед экспортом

Поведенческая согласованность интерфейса

Системное ограничение анимации должно сохранять единый визуальный язык интерфейса. Несогласованность возникает, когда часть Lottie-компонентов отключена, а часть продолжает работать.

Для предотвращения подобных ситуаций используется централизованная политика:

  • единый сервис определения motion-preference
  • единый wrapper над lottie.loadAnimation
  • единая стратегия fallback-рендера

Такая архитектура устраняет разнородность поведения и снижает когнитивную нагрузку интерфейса даже при полном отключении анимации.