prefers-reduced-motion

Как управлять анимацией на сайте и сделать её доступной.

Время чтения: 6 мин

Кратко

Скопировано

Одно из значений директивы @media для проверки пользовательских настроек воспроизведения анимации.

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

С помощью prefers-reduced-motion можно замедлить или полностью отключить анимацию.

Как пишется

Скопировано

У prefers-reduced-motion есть два значения:

  • no-preference — настройки анимации по умолчанию.
  • reduce — анимация отключена.

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

        
          
          @media (prefers-reduced-motion: no-preference) {  html {    scroll-behavior: smooth;  }}
          @media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

        
        
          
        
      

Зачем?

Скопировано

Пользователь может отключить анимацию по разным причинам, например:

  • не все люди воспринимают анимацию одинаково. То, что может показаться плавным и приятным глазу одним, раздражает или отвлекает других (мигающая реклама, сложные параллаксы, автоматическое воспроизведение видео);
  • медицинские аспекты: у некоторых людей могут быть вестибулярные расстройства, при которых даже простая анимация вызывает головокружение, чувство тошноты или судороги;
  • сайты с большим количеством анимации могут быстро снижать заряд батареи мобильных устройств или использовать больше трафика. Например, для автоматического воспроизведения видео потребуется больше данных, чем для показа статического изображения.

Примеры использования

Скопировано

Отключаем или замедляем анимацию

Скопировано

Чтобы отключить анимацию элемента или изменить её скорость, если пользователь явно настроил предпочтение для её уменьшения, можно прописать в CSS следующее:

        
          
          .button {  /*  Весёлая анимация трясущейся кнопки */  animation: shake 300ms linear infinite both;}/*  Полностью отключает анимацию */@media (prefers-reduced-motion: reduce) {  .button {    animation: none;  }}/* Замедляет анимацию в 2 раза */@media (prefers-reduced-motion: reduce) {  .button {    animation: shake 600ms linear infinite both;  }}
          .button {
  /*  Весёлая анимация трясущейся кнопки */
  animation: shake 300ms linear infinite both;
}

/*  Полностью отключает анимацию */
@media (prefers-reduced-motion: reduce) {
  .button {
    animation: none;
  }
}

/* Замедляет анимацию в 2 раза */
@media (prefers-reduced-motion: reduce) {
  .button {
    animation: shake 600ms linear infinite both;
  }
}

        
        
          
        
      

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

        
          
          @media (prefers-reduced-motion: no-preference) {  .button {    animation: shake 300ms linear infinite both;  }}
          @media (prefers-reduced-motion: no-preference) {
  .button {
    animation: shake 300ms linear infinite both;
  }
}

        
        
          
        
      

При втором способе записи есть два преимущества:

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

Плавная прокрутка

Скопировано
        
          
          html {  scroll-behavior: smooth;}
          html {
  scroll-behavior: smooth;
}

        
        
          
        
      

Если установить scroll-behaviour: smooth на <html>, то, когда пользователь нажмёт на якорную ссылку, страница плавно прокрутится до нужной позиции.

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

Можно обернуть scroll-behavior в медиа-запрос, чтобы предотвратить применение плавной прокрутки и просто открыть страницу в нужном месте, если пользователь изменил настройки анимации:

        
          
          @media (prefers-reduced-motion: no-preference) {  html {    scroll-behavior: smooth;  }}
          @media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

        
        
          
        
      

А что с JavaScript?

Скопировано

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

        
          
          const prefersReducedMotion = window.matchMedia(  '(prefers-reduced-motion: reduce)')a.addEventListener('click', () => {  const behavior = prefersReducedMotion.matches ? 'auto' : 'smooth'  window.scrollTo({    x: 0,    y: 0,    behavior  })})
          const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)')

a.addEventListener('click', () => {
  const behavior = prefersReducedMotion.matches ? 'auto' : 'smooth'

  window.scrollTo({
    x: 0,
    y: 0,
    behavior
  })
})

        
        
          
        
      

Оптимизация загрузки стилей и библиотек

Скопировано

Если у вас много CSS, связанного с анимацией, можно вынести стили для её воспроизведения в отдельный файл и не грузить его пользователям, которые отказались от анимации:

        
          
          <link  rel="stylesheet"  href="animations.css"  media="(prefers-reduced-motion: no-preference)">
          <link
  rel="stylesheet"
  href="animations.css"
  media="(prefers-reduced-motion: no-preference)"
>

        
        
          
        
      

Похожим способом можно предотвратить и загрузку тяжёлых библиотек для анимаций. В примере ниже, если пользователь предпочитает уменьшить количество анимации, то функция сделает return и её выполнение прервётся. Благодаря этому не произойдёт импорт GreenSock (GSAP).

        
          
          const prefersReducedMotion = window.matchMedia(  '(prefers-reduced-motion: reduce)')const loadGSAPAndInitAnimations = () => {  if (prefersReducedMotion.matches) return  import('gsap').then((object) => {    const gsap = object.default    // Здесь инициализируем анимацию с использованием GSAP  })};loadGSAPAndInitAnimations()
          const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)')

const loadGSAPAndInitAnimations = () => {
  if (prefersReducedMotion.matches) return

  import('gsap').then((object) => {
    const gsap = object.default
    // Здесь инициализируем анимацию с использованием GSAP
  })
};

loadGSAPAndInitAnimations()

        
        
          
        
      

Поддержка

Скопировано

Имеет отличную поддержку всеми современными браузерами — глобальная поддержка 95.53%.

Системные настройки

Скопировано

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

Windows 10

Настройки > Лёгкость доступа > Дисплей > Показать анимацию в Windows.

Windows 11

Настройки > Универсальный доступ > Визуальные эффекты > Эффекты анимации.

macOS

Системные настройки > Специальные возможности > Дисплей > Уменьшить движение.

iOS

Настройки > Основные > Универсальный доступ > Уменьшить движение.

Android 9+

Настройки > Специальные возможности > Удалить анимацию.

Тестирование и эмуляция

Скопировано

Если хотите посмотреть, как работает prefers-reduced-motion, но не хочется лезть в настройки системы, в браузерах на Chromium можно эмулировать её включение.

Chrome

Скопировано
  1. Откройте средства разработчика (F12).
  2. Зайдите в «Другие инструменты» (More tools).
  3. Выберите вкладку «Отрисовка» (Rendering).
  4. Включите «Эмулировать медиафункцию CSS prefers-reduce-motion» (Emulate CSS media feature prefers-reduce-motion).

Edge

Скопировано
  1. Откройте средства разработчика (F12) и нажмите Ctrl Shift P в Windows/Linux или Command Shift P в macOS — откроется меню команд.
  2. Начните вводить reduced и выберите «Эмулировать CSS prefers-reduced-motion», после чего нажмите Enter.

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

Открыть демо в новой вкладке
        
          
          <picture>  <!-- Анимированный котик -->  <source    srcset="nyancat.gif"    type="image/gif"    media="(prefers-reduced-motion: no-preference)"  >  <!-- Статичный котик -->  <img    src="nyancat.png"    alt="Котик с телом из печенья летит в космосе      и оставляет за собой шлейф из радуги"  ></picture>
          <picture>
  <!-- Анимированный котик -->
  <source
    srcset="nyancat.gif"
    type="image/gif"
    media="(prefers-reduced-motion: no-preference)"
  >

  <!-- Статичный котик -->
  <img
    src="nyancat.png"
    alt="Котик с телом из печенья летит в космосе
      и оставляет за собой шлейф из радуги"
  >
</picture>

        
        
          
        
      

Ссылки

Скопировано