Медиа-запрос 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 по умолчанию не учитывает системные настройки
доступности. Анимация запускается согласно параметрам
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 вовсе. В этом случае интерфейс ограничивается статическим состоянием.
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 обычно выносится в уровень
инициализации компонента.
Обобщённый подход включает:
Пример логики управления:
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Даже при отсутствии 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-анимации содержат:
В режиме reduced motion такие композиции могут оставаться визуально «шумными» даже при остановке. В этих случаях применяется предварительная подготовка ассетов:
Системное ограничение анимации должно сохранять единый визуальный язык интерфейса. Несогласованность возникает, когда часть Lottie-компонентов отключена, а часть продолжает работать.
Для предотвращения подобных ситуаций используется централизованная политика:
lottie.loadAnimationТакая архитектура устраняет разнородность поведения и снижает когнитивную нагрузку интерфейса даже при полном отключении анимации.