Введение в управляемую прокруткой CSS анимацию - Прогресс просмотра

alexei04/03/2025 - 08:26
Введение в управляемую прокруткой CSS анимацию - Прогресс просмотра

Автор Мариана Бельди (Mariana Beldi). Перевод статьи "An Introduction To CSS Scroll-Driven Animations: Scroll And View Progress Timelines".

Прошло 10 лет с тех пор, как в спецификации были представлены анимации, управляемые прокруткой, и после пяти лет разработки мы наконец-то начинаем видеть их на веб-сайтах. Есть рассказываемые истории и игры-лабиринты, а также трехмерные интерфейсы, как в iTunes, и 3D-вращение… Но что именно здесь нового? Не то чтобы мы раньше не видели анимаций, работающих от прокрутки, но то, что мы имеем сейчас, не требует ни JavaScript, ни сторонних библиотек - только чистый CSS. И при том эти анимации запускаются в основном потоке, обеспечивая плавную работу с высокой производительностью и ускорением на графическом процессоре.

Начиная с декабря 2024 года вы можете безопасно использовать анимацию, работающую при прокрутке, в браузерах Chrome. Firefox тоже поддерживает её, но вам нужно будет установить соответствующий флаг. А как Safari? Пока нет, но не волнуйтесь - вы всё равно можете обеспечить бесперебойную работу такой анимации во всех браузерах с помощью полифилла. Просто имейте в виду, что для работы полифилла требуется библиотека JavaScript, поэтому у вас не будет все работать также быстро.

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

Примечание: Все демонстрационные примеры на момент написания статьи работают только в Chrome 116 или более поздних версиях.

Шкала прогресса прокрутки

Шкала прогресса прокрутки связывает анимацию с положением контейнера прокрутки по определённой оси. Таким образом, анимация напрямую связана с прокруткой. По мере прокрутки вперёд также проигрывается и анимация.

Точно так же, как есть два типа анимаций, работающих от прокрутки, также есть два типа шкал анимации прокрутки - анонимные и именованные.

Анонимная шкала анимации прокрутки

Давайте начнём с классического примера: создадим индикатор прогресса прокрутки в верхней части поста в блоге, чтобы отслеживать ход чтения.

В этом примере есть элемент <div> с идентификатором #progress. В CSS вы увидите, что у него есть цвет фона, ширина и высота, и он закреплён в верхней части страницы. Также есть анимация, которая масштабирует его от 0 до 1 по оси X. Если вы знакомы с CSS-анимацией, то все довольно стандартно!

Вот соответствующая часть стилей:


#progress {
  /* ... */
  animation: progressBar 1s linear;
}

@keyframes progressBar {
  from { transform: scaleX(0); }
}

Анимация progressBar запускается один раз и длится одну секунду с линейной функцией тайминга. Чтобы связать эту анимацию с прокруткой, достаточно одной строки в CSS:


animation-timeline: scroll();

Не нужно указывать секунды для продолжительности - время будет определяться поведением прокрутки. И всё! Вы только что создали свою первую анимацию, управляемую прокруткой! Обратите внимание, что направление анимации напрямую связано с направлением прокрутки: при прокрутке вниз индикатор становится шире, а при прокрутке вверх - уже.

Параметры шкалы прокрутки

В анимации в свойстве animation-timeline используется функция scroll(). Она принимает только два параметра: <scroller> и <axis>.

  • <scroller> указывает на контейнер прокрутки и может принимать значения nearest (по умолчанию), root или self.
  • <axis> определяет ось прокрутки и может принимать значения block (по умолчанию), inline, x или y.

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


animation-timeline: scroll(nearest block);

Здесь контейнер прокрутки nearest - это прокрутка корневого HTML-элемента. Таким образом, мы могли бы также написать это следующим образом:


animation-timeline: scroll(root block);

Значение оси block подтверждает, что прокрутка происходит сверху вниз в режиме письма слева направо. Если страница имеет широкую горизонтальную прокрутку и мы хотим анимировать по этой оси, мы могли бы использовать значения inline или x (в зависимости от того, хотим ли мы, чтобы направление прокрутки всегда было слева направо или менялось в зависимости от режима письма).

Мы рассмотрим значения self и inline позже на более сложных примерах, но лучший способ понять принцип работы этих параметров - это поэкспериментировать со всеми комбинациями. И в этом вам поможет инструмент от Bramus. Потратьте несколько минут, прежде чем мы перейдём к следующему свойству, связанному анимацией прокрутки.

Свойство animation-range

Свойство animation-range для шкалы прокрутки определяет, какая часть прокручиваемого содержимого управляет началом и окончанием анимации в зависимости от положения прокрутки. Это позволяет определить, когда анимация начинается или заканчивается при прокрутке внутри контейнера.

По умолчанию свойство animation-range имеет значение normal, что по сути является краткой формой записи следующих свойств:


animation-range-start: normal;
animation-range-end: normal;

Это переводится как 0% (начало) и 100% (конец) в прокручиваемой анимации:


animation-range: normal normal;

...что аналогично:


animation-range: 0% 100%;

Вы можете указать любые единицы длины CSS или даже задать вычисляемые значения. Например, предположим, что есть нижний колонтитул высотой 500px. Он заполнен баннерами, рекламой и связанными с ними публикациями. Я не хочу, чтобы индикатор прогресса прокрутки включал что-либо из этого в процесс чтения. Я хочу, чтобы анимация начиналась сверху и заканчивалась за 500px до нижней части. Тогда мы просто указываем:


animation-range: 0% calc(100% - 500px);

Вот так просто мы рассмотрели ключевые свойства анимации, управляемой прокруткой. Готовы сделать следующий шаг?

Именованная шкала анимации прокрутки

Допустим, я хочу использовать положение прокрутки другого контейнера для той же анимации. Свойство scroll-timeline-name позволяет указать, с каким контейнером прокрутки должна быть связана эта анимация. Вы указываете имя (например, --my-scroll-timeline), относящееся к контейнеру прокрутки, который вы хотите использовать. Этот контейнер будет управлять ходом анимации по мере прокрутки пользователем.

Затем нужно определить ось прокрутки для этого нового контейнера с помощью свойства scroll-timeline-axis, которое сообщит анимации, какая ось прокрутки будет запускать движение. Вот как это выглядит:


.my-class { 
  /* Это мой новый контейнер прокрутки */
  scroll-timeline-name: --my-custom-name;
  scroll-timeline-axis: inline;
}

Если вы не укажите ось, то по умолчанию будет использовано значение block. Однако вы также можете использовать сокращённую запись scroll-timeline для объединения имени и оси в одном объявлении:


.my-class { 
  /* Короткая запись для определения контейнера и оси прокрутки */
  scroll-timeline: --my-custom-name inline;
}

Я думаю, что всё это проще понять на практическом примере. Вот тот же индикатор прогресса, с которым мы уже имели дело, но со значением прокрутки inline (т. е. по оси x):

У нас работает две анимации:

  1. Индикатор прогресса становится шире при прокрутке по горизонтальной оси.
  2. Цвет фона контейнера меняется по мере прокрутки.

Структура HTML выглядит следующим образом:


<div class="gallery">
  <div class="gallery-scroll-container">
    <div class="gallery-progress" role="progressbar" aria-label="progress"></div>
    <img src="image1.svg" alt="Alt text" draggable="false" width="500">
    <img src="image2.svg" alt="Alt text" draggable="false" width="500">
    <img src="image3.svg" alt="Alt text" draggable="false" width="500">
  </div>
</div>

В данном случае элемент gallery-scroll-container имеет горизонтальную прокрутку и меняет цвет фона при прокрутке. Для этого можно использовать свойство animation-timeline: scroll(self inline). Однако мы также хотим, чтобы элемент gallery-progress использовал ту же прокрутку для своей анимации.

Элемент gallery-progress стоит первым внутри элемента gallery-scroll-container, и, если у него не будет абсолютного позиционирования, то при прокрутке он потеряется. Но когда мы задаем ему абсолютное позиционирование, он больше не занимает место в обычном потоке документа, и это влияет на его взаимодействие с родительским и другими элементами. Нам нужно указать, к какому контейнеру прокрутки мы хотим его привязать.

Вот здесь и пригодится присвоение имени контейнеру прокрутки. Задав для элемента gallery-scroll-container имя и ось анимации прокрутки, мы можем гарантировать синхронизацию обеих анимаций с одной и той же прокруткой:


.gallery-scroll-container {
  /* ... */
  animation: bg steps(1);
  scroll-timeline: --scroller inline;
}

И использовать эту прокрутку для определения своего собственного свойства animation-timeline:


.gallery-scroll-container {
  /* ... */
  animation: bg steps(1);
  scroll-timeline: --scroller inline;
  animation-timeline: --scroller;
}

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


.gallery-progress {
  /* ... */
  animation: progressBar linear;
  animation-timeline: --scroller;
}

Это позволяет обеим анимациям (растущий индикатор прогресса и изменение цвета фона) одновременно реагировать на одну прокрутку, даже если это отдельные элементы и анимации.

Свойство timeline-scope

Что произойдёт, если мы захотим анимировать что-то в зависимости от положения прокрутки элемента того же уровня или даже более раннего предка? Здесь в игру вступает свойство timeline-scope. Оно позволяет нам расширить область действия прокрутки за пределы поддерева текущего элемента. Значением timeline-scope должен быть пользовательский идентификатор, который является "тире-идентификатором".

Давайте проиллюстрируем это на новом примере. На этот раз при прокрутке в одном контейнере запускается анимация в другом контейнере:

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


<div class="main-container">
  <div class="sardinas-container">
    <img ...>
  </div>

  <div class="scroll-container">
    <p>Длинный текст...</p>
  </div>
</div>

Здесь только элемент .scroll-container имеет прокручиваемый контент, поэтому сначала давайте присвоим ему имя:


.scroll-container {
  /* ... */
  overflow-y: scroll;
  scroll-timeline: --containerText;
}

Обратите внимание, что здесь не указана ось прокрутки, так как по умолчанию используется значение block (прокрутка по вертикали), и это именно то значение, которое нужно.

Давайте перейдём к изображению внутри элемента .sardinas-container. Нам нужно, чтобы это изображение анимировалось при прокрутке элемента .scroll-container. Для этого мы добавили имя из свойства scroll-timeline в свойство animation-timeline:


.sardinas-container img {
  /* ... */
  animation: moveUp steps(6) both;
  animation-timeline: --containerText;
}

Тем не менее, на этом этапе анимация всё еще работать не будет, потому что .scroll-container не связан напрямую с изображениями. Чтобы все заработало, нам нужно расширить область действия имени из свойства scroll-timeline. Это делается путём добавления свойства timeline-scope к родительскому элементу (или более раннему предку), общему для обоих элементов:


.main-container {
  /* ... */
  timeline-scope: --containerText;
}

При такой настройке прокрутка элемента .scroll-container теперь будет управлять анимацией изображения внутри элемента .sardinas-container!

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

Шкала прогресса просмотра

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

Шкала прогресса просмотра - это второй тип анимации, управляемой прокруткой. Она отслеживает элемент, когда он входит в область прокрутки (видимую область прокручиваемого контента) или выходит из неё.

У нас есть анонимные и именованные шкалы прогресса просмотра, а также анонимные и именованные анимации прогресса прокрутки. Давайте разберёмся с ними.

Анонимная шкала прогресса просмотра

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

Допустим, мы хотим анимировать изображение, которое постепенно появляется в области прокрутки. Непрозрачность изображения будет меняться от 0 до 1. Вот как можно написать эту же анимацию в классическом CSS с помощью правила @keyframes:


img {
  /* ... */
  animation: fadeIn 1s;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

Это здорово, но мы хотим, чтобы анимация fadeIn включалась, когда изображение появляется в поле зрения. В противном случае анимация будет похожа на дерево, которое падает в лесу, и никто не видит этого... была ли вообще анимация? Мы никогда не узнаем!

У нас есть функция view(), которая позволяет создать анимацию прогресса просмотра с помощью одной строки CSS:


img {
  /* ... */
  animation: fadeIn;
  animation-timeline: view();
}

И обратите внимание, что нам больше не нужно объявлять animation-duration, как в классическом CSS. Анимация больше не привязана ко времени, а привязана к пространству. Анимация запускается, когда изображение становится видимым в области прокрутки.

Параметры свойства шкалы просмотра

Как и свойство шкалы прокрутки, свойство шкалы просмотра также принимает параметры, которые позволяют выполнять более тонкую настройку:


animation-timeline: view( );

  • <inset>
    Управляет началом и окончанием анимации в зависимости от видимости элемента в области прокрутки. Определяет расстояние между краями области прокрутки и отслеживаемым элементом. Значение по умолчанию - auto, но также можно использовать процентное значение длины, а также начальное и конечное значения.
  • <axis>
    Определяет, к какой оси (горизонтальной или вертикальной) привязана анимация. По умолчанию используется значение block, что означает отслеживание вертикального движения. Вы также можете использовать значение inline для отслеживания горизонтального движения или просто x или y.

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


img {
  animation-timeline: view(20% block);
}

В данном случае:

  1. Анимация начинается, когда изображение занимает 20% видимой области прокрутки.
  2. Анимация запускается вертикальной прокруткой.

Эффект параллакса

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


img {
  animation: parallaxMove 1s;
  animation-timeline: view();
}

@keyframes parallaxMove {
  to { transform: translateY(-50px); }
}

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

Свойство animation-range

Использование CSS свойства animation-range со шкалой просмотра позволяет определить, какая часть видимости элемента в области просмотра контролирует начальную и конечную точки прогресса анимации. Это можно использовать для точной настройки начала и окончания анимации в зависимости от видимости элемента в области просмотра.

При значении по умолчанию normal отслеживается полная видимость элемента с момента его появления в области прокрутки до полного исчезновения. Это представляется следующим образом:


animation-range: normal normal;
/* Эквивалентно */
animation-range: cover 0% cover 100%;

Или еще проще:


animation-range: cover;

Есть шесть возможных значений:

  1. cover
    Отслеживает полную видимость элемента с момента его появления в области прокрутки до момента, когда он полностью покинет её.
  2. contain
    Отслеживает, когда элемент полностью отображается в области прокрутки, с момента, когда он полностью отображается, до момента, когда он перестаёт отображаться.
  3. entry
    Отслеживает элемент с момента его появления в области прокрутки до полного заполнения области прокрутки.
  4. exit
    Отслеживает элемент с момента его появления, пока он не выйдет за пределы области прокрутки.
  5. entry-crossing
    Отслеживает элемент, когда он пересекает начальную границу области прокрутки, от начала до полного пересечения.
  6. exit-crossing
    Отслеживает элемент, когда он пересекает конечную границу области прокрутки, от начала до полного пересечения.

Вы можете комбинировать различные значения для управления начальной и конечной точками диапазона анимации. Например, вы можете сделать так, чтобы анимация начиналась, когда элемент попадает в область прокрутки, и заканчивалась, когда он из неё выходит:


animation-range: entry exit;

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


animation-range: entry 50% exit 50%;

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

Определение диапазона внутри правила @keyframes

Одной из мощных функций значений диапазона анимации временной шкалы является возможность их использования внутри @keyframes:

В данном примере воспроизводится две различные анимации:

  1. slideIn
    Когда элемент попадает в область прокрутки, он постепенно становится видимым.
  2. slideOut
    Когда элемент уходит из области прокрутки, он постепенно исчезает.

@keyframes slideIn {
  from {
    transform: scale(.8) translateY(100px); 
    opacity: 0;
  }
  to { 
    transform: scale(1) translateY(0); 
    opacity: 1;
  }
}

@keyframes slideOut {
  from {
    transform: scale(1) translateY(0); 
    opacity: 1;    
  }
  to { 
    transform: scale(.8) translateY(-100px); 
    opacity: 0 
  }
}

Так пришлось бы кодировать эти анимации раньше. Теперь же мы можем объединить эти две анимации с помощью расширенного использования значений entry и exit свойства animation-range. Это позволяет упростить старый код до одной анимации, которая подходит для обоих случаев:


@keyframes slideInOut {
  /* Анимация, когда элемент входит в область прокрутки */
  entry 0% {
    transform: scale(.8) translateY(100px); 
    opacity: 0;
  }
  entry 100% { 
    transform: scale(1) translateY(0); 
    opacity: 1;
  }
  /* Анимация, когда элемент выходит из области прокрутки */
  exit 0% {
    transform: scale(1) translateY(0); 
    opacity: 1;    
  }
  exit 100% { 
    transform: scale(.8) translateY(-100px); 
    opacity: 0;
  }
}

  • entry 0%
    Определяет состояние элемента в начале его входа в область прокрутки (прозрачен и невидим).
  • entry 100%
    Определяет состояние, когда элемент полностью вошёл в область прокрутки (полностью виден).
  • exit 0%
    Начинает отслеживать элемент, когда он начинает выходить за пределы области прокрутки (полностью виден).
  • exit 100%
    Определяет состояние, когда элемент полностью покинул область прокрутки (прозрачен и невидим).

Такой подход позволяет плавно анимировать элемента при его входе в область прокрутки и выходе из неё в рамках одного блока @keyframes.

Именованное свойство view-timeline и свойство timeline-scope

Концепция использования свойства view-timeline с именованной временной шкалой и связывания ее с разными элементами может значительно расширить возможности анимации, управляемой прокруткой. В этом случае соотносим анимацию, управляемую прокруткой, с анимацией несвязанных абзацев в структуре DOM, используя именованные шкалы просмотра и свойство timeline-scope.

Свойство view-timeline работает так же, как и свойство scroll-timeline. Это сокращённая запись для объявления свойств view-timeline-name и view-timeline-axis в одной строке. Однако отличие от scroll-timeline заключается в том, что мы можем связать анимацию элемента с моментом, когда связанные элементы попадают в область прокрутки. Я взяла предыдущий пример и добавила анимацию к абзацам, чтобы вы могли увидеть, как меняется непрозрачность текста при прокрутке изображений слева:

Этот пример выглядит немного громоздким, но мне было трудно найти более подходящий пример для демонстрации данных возможностей. Для каждого изображения в контейнере с вертикальной прокруткой определяется именованное свойство view-timeline с уникальным идентификатором:


.vertical-scroll-container img:nth-of-type(1) { view-timeline: --one; }
.vertical-scroll-container img:nth-of-type(2) { view-timeline: --two; }
.vertical-scroll-container img:nth-of-type(3) { view-timeline: --three; }
.vertical-scroll-container img:nth-of-type(4) { view-timeline: --four; }

Благодаря этому временная шкала прокрутки каждого изображения будет иметь свое собственное имя, например --one для первого изображения, --two для второго и так далее.

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


.vertical-text p:nth-of-type(1) { animation-timeline: --one; }
.vertical-text p:nth-of-type(2) { animation-timeline: --two; }
.vertical-text p:nth-of-type(3) { animation-timeline: --three; }
.vertical-text p:nth-of-type(4) { animation-timeline: --four; }

Тем не менее, поскольку изображения и абзацы не связаны напрямую в DOM, нам нужно объявить свойство timeline-scope для их общего предка. Это гарантирует, что на именованные временные шкалы (--one, --two и так далее) можно ссылаться и использовать их совместно между элементами:


.porto {
  /* ... */
  timeline-scope: --one, --two, --three, --four;
}

Объявив свойство timeline-scope со всеми именованными временными шкалами (--one, --two, --three, --four), и изображения и абзацы могут участвовать в одной и той же логике временной шкалы прокрутки, несмотря на то, что находятся в разных частях дерева DOM.

Заключительные замечания

В этой статье мы рассмотрели большую часть того, что в настоящее время, т. е. на декабрь 2024 года, определено в спецификации по CSS-анимации при прокрутке Уровень 1. Но мне хотелось бы выделить несколько ключевых моментов, которые помогли мне лучше понять эти новые правила, которые вы, возможно, не найдёте в спецификации напрямую:

  • Необходимость контейнера прокрутки
    Это может показаться очевидным, но для работы анимации, управляемой прокруткой, необходим контейнер прокрутки. Проблемы часто возникают при изменении размера таких элементов, как текст или контейнеры, или при тестировании анимации на больших экранах, что приводит к исчезновению области прокрутки.
  • Влияние position: absolute
    Использование абсолютного позиционирования иногда может повлиять на ожидаемое поведение анимации, управляемой прокруткой. Когда применяется свойство position: absolute, взаимосвязь между элементами и их родительскими элементами становится сложной.
  • Отслеживание начального состояния элемента
    Браузер оценивает состояние элемента до применения каких-либо преобразований (например, translate). Это влияет на то, когда начинается анимация, особенно это касается временной последовательности просмотра. Ваша анимация может запуститься раньше или позже ожидаемого времени из-за начального состояния элемента.
  • Старайтесь не скрывать переполнение
    Использование свойства overflow: hidden может нарушить механизм поиска прокрутки в анимациях, управляемых прокруткой. Рекомендуемое решение - использовать свойство overflow: clip.
  • Производительность
    Для достижения наилучших результатов используйте для анимации свойства, оптимизированные для графического процессора, такие как трансформации, непрозрачность и некоторые фильтры. Это позволит избежать сложных вычислений для компоновки и перерисовки. С другой стороны, анимации по таким свойствам, как width, height или box-shadow может замедлить работу, поскольку они требуют повторного рендеринга.
  • Используйте will-change с умом
    Вы можете использовать это свойство, чтобы передавать элементы для обработки графическим процессором, но применяйте его с осторожностью. Чрезмерное использование свойство will-change может привести к чрезмерному использованию памяти, поскольку браузер резервирует ресурсы, даже если анимация не меняется.
  • Порядок имеет значение
    Если вы используете короткое свойство animation, всегда ставьте свойство animation-timeline после него.
  • Прогрессивное усовершенствование и доступность
    Объединяйте медиазапросы для уменьшения количества анимаций с правилом @supports, чтобы анимация применялась только в том случае, если у пользователя нет ограничений на анимацию, а браузер её поддерживает.

Например:


@media screen and (prefers-reduce-motion: no-preference) {
  @supports ((animation-timeline: scroll()) and (animation-range: 0% 100%)) { 
    .my-class {
      animation: moveCard linear both;    
      animation-timeline: view(); 
    }
  } 
}

Основная сложность, с которой я столкнулась при создании демонстрационных примеров, была связана скорее с CSS, чем с анимацией прокрутки. Иногда создать макет и сгенерировать прокрутку было сложнее, чем применить анимацию прокрутки. Кроме того, некоторые вещи, которые поначалу сбивали меня с толку, продолжают развиваться, и некоторых из них больше нет (не забывайте, что разработка ведётся уже более пяти лет!):

  • Оси x и y
    Раньше их называли "горизонтальной" и "вертикальной" осями, и хотя Firefox всё ещё поддерживает старую терминологию, она была обновлена.
  • Старый @scroll-timeline
    Раньше для объявления временных последовательностей прокрутки использовалось правило @scroll-timeline, но в последней версии спецификации это изменилось.
  • Управляемые прокруткой и связанные с прокруткой анимации
    Изначально анимации, управляемые прокруткой, назывались анимациями, связанными с прокруткой. Если вы встретите этот устаревший термин в статьях, проверьте, обновлено ли содержимое в соответствии с последней спецификацией, особенно в отношении таких функций, как timeline-scope.