Отключение анимаций для пользователей с ограничениями

Современные интерфейсы обязаны учитывать не только визуальную привлекательность, но и состояние пользователей. Анимации при прокрутке, реализованные с помощью AOS, могут вызывать дискомфорт у людей с вестибулярными нарушениями, когнитивными особенностями или повышенной чувствительностью к движению. Веб-стандарты предусматривают механизм для обработки подобных ситуаций — медиазапрос prefers-reduced-motion.

Медиазапрос prefers-reduced-motion

CSS предоставляет специальный медиазапрос:

@media (prefers-reduced-motion: reduce) {
  /* стили для пользователей, отключивших анимацию */
}

Если в системе пользователя включено уменьшение анимации, этот запрос возвращает значение reduce. Это основной сигнал для отключения или упрощения визуальных эффектов.

Поведение AOS при reduced motion

Библиотека AOS по умолчанию не отключает анимации автоматически. Требуется явная настройка поведения. Наиболее распространённые подходы:

1. Полное отключение AOS

if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  AOS.init({
    disable: true
  });
} else {
  AOS.init();
}

Параметр disable полностью выключает все анимации библиотеки.

2. Отключение через функцию

AOS.init({
  disable: function () {
    return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  }
});

Этот вариант гибче, поскольку проверка выполняется при инициализации.

Управление через CSS

Даже при отключении AOS важно корректно отобразить элементы. По умолчанию AOS скрывает элементы до момента анимации (используется opacity: 0 и трансформации). Поэтому требуется переопределение стилей:

@media (prefers-reduced-motion: reduce) {
  [data-aos] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

Это гарантирует, что элементы будут сразу видимыми без анимационных эффектов.

Частичное упрощение анимаций

Иногда полное отключение нежелательно — допустимо оставить минимальные эффекты:

AOS.init({
  duration: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 0 : 800,
  easing: 'ease-out'
});

При reduced motion длительность устанавливается в 0, что устраняет движение, но сохраняет логику появления.

Использование пользовательских настроек

Дополнительно возможно внедрение ручного переключателя:

const reduceMotion = localStorage.getItem('reduceMotion');

AOS.init({
  disable: reduceMotion === 'true'
});

Кнопка управления:

document.querySelector('#toggle-motion').addEventListener('click', () => {
  const current = localStorage.getItem('reduceMotion') === 'true';
  localStorage.setItem('reduceMotion', !current);
  location.reload();
});

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

События изменения предпочтений

Пользователь может изменить настройки системы во время работы страницы. Для отслеживания используется событие change:

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

mediaQuery.addEventListener('change', (event) => {
  if (event.matches) {
    AOS.refreshHard();
  }
});

refreshHard() пересоздаёт состояние библиотеки.

Влияние на производительность

Отключение анимаций снижает нагрузку на:

  • GPU (меньше трансформаций)
  • CPU (меньше вычислений)
  • батарею мобильных устройств

Особенно заметно на слабых устройствах и при большом количестве элементов с data-aos.

Лучшие практики

Избегать резких движений

  • анимации с большими смещениями по оси Y
  • масштабирование (zoom-in, zoom-out)

Минимизировать длительность

  • при необходимости использовать значения до 300ms

Не использовать параллакс

  • эффект параллакса особенно проблематичен для чувствительных пользователей

Проверять контент без анимаций

  • интерфейс должен оставаться логичным и читабельным

Типичные ошибки

Элементы остаются скрытыми

  • не переопределены стили opacity и transform

Игнорирование prefers-reduced-motion

  • отсутствие медиазапросов или JS-проверки

Смешение логики

  • частичное отключение без учета CSS

Неправильная инициализация

  • AOS вызывается до проверки условий

Интеграция с фреймворками

В React:

useEffect(() => {
  const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  AOS.init({
    disable: reduceMotion
  });
}, []);

В Vue:

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

  AOS.init({
    disable: reduceMotion
  });
}

Доступность как часть архитектуры

Поддержка ограничений движения должна закладываться на этапе проектирования:

  • проектирование без зависимости от анимации
  • прогрессивное улучшение (progressive enhancement)
  • тестирование с включённым reduced motion

Такой подход делает интерфейс устойчивым, гибким и соответствующим современным стандартам доступности.