Отключение анимаций для слабых устройств

Анимации с использованием anime.js могут быть ресурсоёмкими, особенно на устройствах с ограниченной производительностью или при слабом интернет-соединении. В таких случаях важно предусмотреть механизмы отключения анимаций, чтобы интерфейс оставался отзывчивым и не вызывал лагов или нагрева устройства.

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


Использование CSS-медиа-запроса prefers-reduced-motion

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

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

if (prefersReducedMotion) {
    console.log('Анимации отключены в соответствии с предпочтениями пользователя');
} else {
    anime({
        targets: '.box',
        translateX: 250,
        duration: 1000,
        easing: 'easeInOutQuad'
    });
}

Объяснение ключевых моментов:

  • window.matchMedia('(prefers-reduced-motion: reduce)') возвращает объект MediaQueryList.
  • Свойство matches будет true, если пользователь активировал опцию сокращения анимаций в настройках ОС.
  • В блоке if можно полностью пропускать вызовы anime() или использовать упрощённые анимации.

Проверка производительности устройства

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

const isLowEndDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 2;

if (isLowEndDevice) {
    console.log('Упрощение анимаций для слабого устройства');
    // Упрощённая анимация
    anime({
        targets: '.box',
        translateX: 250,
        duration: 500,
        easing: 'linear'
    });
} else {
    // Полная анимация
    anime({
        targets: '.box',
        translateX: 250,
        duration: 1000,
        easing: 'easeInOutQuad'
    });
}

Пояснения:

  • navigator.hardwareConcurrency показывает количество логических процессоров.
  • Для устройств с ≤2 ядрами анимации сокращаются или полностью заменяются статическими переходами.
  • Применение линейного easing и уменьшенной длительности снижает нагрузку на CPU.

Программное отключение отдельных эффектов

Иногда необходимо selectively отключать только часть анимаций, оставляя основные переходы. Для этого можно использовать флаг состояния анимации:

let animationsEnabled = !(prefersReducedMotion || isLowEndDevice);

if (animationsEnabled) {
    anime.timeline({loop: true})
        .add({
            targets: '.circle',
            scale: [0, 1],
            opacity: [0, 1],
            duration: 800,
            easing: 'easeOutElastic(1, .8)'
        })
        .add({
            targets: '.circle',
            translateX: 200,
            duration: 1200,
            easing: 'easeInOutQuad'
        });
} else {
    // Статическое состояние
    document.querySelectorAll('.circle').forEach(el => {
        el.style.transform = 'translateX(200px) scale(1)';
        el.style.opacity = '1';
    });
}

Принцип работы:

  • animationsEnabled комбинирует проверку системных настроек и производительности.
  • Если анимации отключены, элементы получают конечные стили без анимации.
  • Использование anime.timeline() позволяет легко включать или исключать целые блоки анимаций.

Упрощение анимаций вместо полного отключения

Полное удаление анимаций не всегда оптимально. Можно заменить сложные эффекты на более лёгкие трансформации, такие как:

  • translate вместо rotate3d
  • opacity вместо сложных кривых движения
  • уменьшение количества повторов и таймлайнов
anime({
    targets: '.icon',
    translateY: 20,   // вместо сложного path движения
    duration: 400,
    easing: 'linear'
});

Преимущество: визуальный отклик остаётся, а нагрузка на устройство минимизируется.


Динамическое переключение состояния анимаций

Возможна реализация динамического включения/отключения анимаций на лету, например, при изменении системных настроек:

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

function handleReducedMotionChange(event) {
    if (event.matches) {
        anime.remove('.box'); // остановка всех текущих анимаций
        document.querySelector('.box').style.transform = 'translateX(250px)';
    } else {
        anime({
            targets: '.box',
            translateX: 250,
            duration: 1000,
            easing: 'easeInOutQuad'
        });
    }
}

mediaQuery.addEventListener('change', handleReducedMotionChange);

Ключевые моменты:

  • anime.remove(target) немедленно прекращает текущие анимации на целевом элементе.
  • Использование события change позволяет реагировать на изменение настроек пользователя без перезагрузки страницы.

Рекомендации по практическому применению

  • Приоритет производительности: для слабых устройств сокращать или отключать анимации.
  • Системные настройки: всегда учитывать prefers-reduced-motion.
  • Адаптивность: динамически изменять поведение в зависимости от возможностей устройства.
  • Минимизация DOM-операций: чем меньше элементов участвуют в анимации, тем меньше нагрузка.
  • Упрощение сложных эффектов: замена тяжёлых трансформаций на лёгкие translate/opacity.

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