Как создать индикатор прокрутки

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

Рекомендации по внедрению

Чтобы создать индикатор прогресса прокрутки, вам понадобятся две вещи:

  1. Элемент, который будет использоваться в качестве индикатора выполнения. Обычно это элемент position: fixed или position: absolute, который остается видимым при прокрутке.
  2. Анимация, связанная с положением прокрутки.

Вот что можно сделать:

  • Сначала создайте элемент HTML, который будет служить индикатором выполнения. Этот элемент можно оформить по своему вкусу.
  • Затем в CSS определите анимацию @keyframes, которая масштабирует индикатор выполнения. Обычно элемент масштабируется от scaleX(0) до scaleX(1).
  • Наконец, примените эту анимацию к элементу индикатора выполнения и установите для его свойства animation-timeline значение scroll-timeline. Это указывает браузеру управлять ходом анимации на основе положения прокрутки ближайшего предка.

Пример кода

Этот код увеличивает элемент #progress при прокрутке, используя анонимную временную шкалу прокрутки, созданную функцией scroll().

@media (prefers-reduced-motion: no-preference) {
  @supports ((animation-timeline: scroll())) {
    @keyframes grow-progress {
      from { transform: scaleX(0); }
      to { transform: scaleX(1); }
    }

    #progress {
      position: fixed;
      left: 0; top: 0;
      width: 100%; height: 1em;
      background: red;

      transform-origin: 0 50%;
      animation: grow-progress auto linear;
      animation-timeline: scroll();
    }
  }
}

Из-за своего расположения в DOM функция scroll() будет отслеживать ближайший предок-скроллер в направлении block, которым здесь является корневой скроллер.

<body>
  <!-- MANDATORY: Purely decorative visual scroll progress bars MUST set aria-hidden="true" to remove the empty element from the assistive technology reading tree -->
  <div id="progress" aria-hidden="true"></div>
</body>

Этот код увеличивает элемент #progress при прокрутке с помощью именованной временной шкалы прокрутки, созданной свойством scroll-timeline.

@media (prefers-reduced-motion: no-preference) {
  @supports ((animation-timeline: scroll())) {
    @keyframes grow-progress {
      from { transform: scaleX(0); }
      to { transform: scaleX(1); }
    }

    :root {
      scroll-timeline: --tl block;
    }

    #progress {
      position: fixed;
      left: 0; top: 0;
      width: 100%; height: 1em;
      background: red;

      transform-origin: 0 50%;
      animation: grow-progress auto linear;
      animation-timeline: --tl;
    }
  }
}

Рекомендации

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

  • РЕКОМЕНДУЕТСЯ включить обнаружение функций. Не все браузеры поддерживают анимацию, управляемую прокруткой. Используйте @supports (animation-timeline: scroll()), чтобы проверить поддержку и предоставить резервный вариант для браузеров, которые ее не поддерживают.
    • НЕ ИСПОЛЬЗУЙТЕ пакет scroll-timeline-polyfill для резервной стратегии, так как он неполный и имеет много известных проблем.
    • Если анимация используется только в декоративных целях, выберите прогрессивное улучшение и НЕ добавляйте резервный вариант.
  • РЕКОМЕНДУЕТСЯ удалять чисто декоративные элементы из потоков чтения технологий специальных возможностей. Применяйте aria-hidden="true" к чисто визуальным индикаторам прокрутки, чтобы программы чтения с экрана не сталкивались с пустыми безымянными узлами.
  • Уважайте предпочтения пользователей. Некоторые пользователи предпочитают, чтобы на веб-страницах было меньше движения. Используйте медиазапрос prefers-reduced-motion, чтобы отключить или уменьшить анимацию для этих пользователей.
  • РЕКОМЕНДУЕТСЯ анимировать только эффективные свойства CSS. Чтобы анимация была максимально плавной, анимируйте свойства, которые могут обрабатываться потоком компоновщика браузера, например transform и opacity. Анимация других свойств, таких как width или height, может привести к проблемам производительности.
  • РЕКОМЕНДУЕТСЯ использовать правильный порядок объявления. При использовании сокращенного свойства animation объявляйте animation-timeline после него, чтобы сокращенное свойство не сбрасывало временную шкалу.

При использовании функции scroll() для создания анимации, управляемой прокруткой:

  • НЕОБЯЗАТЕЛЬНО. Укажите, какой скроллер вы хотите использовать, если это не ближайший предок. Для этого используйте scroll(root) или scroll(self).
    • Если root, nearest или self недостаточно, используйте именованную временную шкалу прокрутки.
  • НЕОБЯЗАТЕЛЬНО. Укажите ось, которую нужно отслеживать. Если таргетинг настроен не на ось block по умолчанию (например, при горизонтальной прокрутке), укажите, какую ось нужно отслеживать, с помощью scroll(block) или scroll(inline).

При использовании свойства scroll-timeline для создания анимации, управляемой прокруткой:

  • РЕКОМЕНДУЕТСЯ использовать для названия CSS-класс <dashed-ident>.
  • НЕОБЯЗАТЕЛЬНО. Укажите ось, которую нужно отслеживать. Если таргетинг настроен не на ось block по умолчанию (например, при горизонтальной прокрутке), укажите, какую ось нужно отслеживать с помощью scroll-timeline-axis.
  • РЕКОМЕНДУЕТСЯ убедиться, что область поиска работает. Если элемент, объявляющий scroll-timeline, не является предком анимированного элемента в плоском дереве, сделайте имя scroll-timeline видимым, используя timeline-scope для общего предка.

Резервные стратегии

Для браузеров, которые не поддерживают анимацию на основе прокрутки, можно использовать резервный вариант, чтобы воссоздать визуальные эффекты. Резервные варианты обычно создаются с помощью прослушивателя прокрутки (для эффектов ScrollTimeline) или IntersectionObserver API (для эффектов ViewTimeline).

В браузерах со встроенной поддержкой анимации на основе прокрутки ВСЕГДА используйте нативную реализацию CSS, так как она более эффективна.

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

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

<script>
  if (!CSS.supports('animation-timeline', 'scroll()')) {
    const progress = document.querySelector('#progress');

    window.addEventListener('scroll', () => {
      const scrollable = document.documentElement.scrollHeight - window.innerHeight;
      const scrolled = window.scrollY;
      const progressPercentage = (scrolled / scrollable);

      progress.style.transform = `scaleX(${progressPercentage})`;
    });
  }
</script>