Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как сделать индикатор прочтения страницы

Короткий ответ

Привяжите анимацию не ко времени, а к прокрутке страницы:

.progress {
  position: fixed; top: 0; left: 0; width: 100%; height: 4px;
  background: tomato; transform-origin: left;
  animation: grow linear;
  animation-timeline: scroll(root);
}
 
@keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

animation-timeline: scroll(root) заменяет секунды на положение прокрутки: в начале страницы анимация на 0%, в конце — на 100%. Полоса растёт от scaleX(0) до полной ширины. JavaScript не нужен.

Живой пример в блоке с прокруткой

Без аргумента scroll() берёт ближайший прокручиваемый родитель. Прокрутите текст:

<style>
  .article { height: 160px; overflow: auto; font: 14px/1.6 system-ui, sans-serif; border: 1px solid #ddd; }
  .bar { position: sticky; top: 0; height: 4px; background: tomato; transform-origin: left;
    animation: grow linear; animation-timeline: scroll(); }
  @keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  .article p { margin: 12px; }
</style>
 
<div class="article">
  <div class="bar"></div>
  <p>Scroll down to fill the bar.</p>
  <p>CSS can tie an animation to the scroll position instead of time.</p>
  <p>The bar grows as you read and reaches full width at the end.</p>
  <p>No JavaScript is involved: the browser does all the work.</p>
  <p>The same trick works for the whole page with scroll(root).</p>
  <p>You have reached the end.</p>
</div>

position: sticky держит полосу вверху блока во время прокрутки.

Запасной вариант

Анимации по прокрутке есть ещё не во всех браузерах. Там, где их нет, свойство animation-timeline пропускается, анимация без длительности заканчивается мгновенно, и полоса застывает на всю ширину. Страница не ломается, но индикатор врёт. Поэтому оберните стили полосы в @supports (animation-timeline: scroll()) — тогда в старых браузерах её просто не будет. Если индикатор нужен везде, его можно двигать несколькими строками JavaScript по событию scroll.

Частая ошибка

Записывать animation-timeline перед animation. Сокращённое свойство animation сбрасывает animation-timeline в значение по умолчанию, и анимация снова идёт по времени, а не по прокрутке. animation-timeline всегда ставьте после animation.

Функции из этого ответа

  • animation-timeline — Связывает CSS-анимацию с прокруткой вместо времени: анимация продвигается по мере прокрутки страницы или элемента.
  • scroll() — Создают безымянные шкалы прокрутки для `animation-timeline`: `scroll()` следит за прокручиваемым контейнером, `view()` — за проходом самого элемента через видимую область.
  • @keyframes — Описывает шаги анимации, которую затем запускают свойством `animation`.
  • position — Как позиционируется элемент: в обычном потоке или по смещениям.
  • @supports — Применяет правила, только если браузер поддерживает указанное свойство, значение или селектор.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.