С декабря 2024 года вы можете безопасно использовать анимацию при прокрутке в Chrome. Firefox тоже поддерживает её, но вам нужно будет включить флаг. Safari? Пока нет, но не волнуйтесь — вы всё равно можете обеспечить бесперебойную работу во всех браузерах с помощью полифилла. Просто имейте в виду, что для добавления полифилла требуется библиотека JavaScript, поэтому вы не получите такого же повышения производительности.
В этой статье мы рассмотрим последнюю опубликованную W3C версию и изучим два типа временных шкал с прокруткой — временные шкалы с прокруткой и временные шкалы с просмотром. К концу статьи я надеюсь, что вы будете знакомы с обеими временными шкалами и сможете не только отличать их друг от друга, но и уверенно использовать их в своей работе.
Временная шкала прогресса прокрутки связывает временную шкалу анимации с положением прокрутки контейнера прокрутки по определённой оси. Таким образом, анимация напрямую связана с прокруткой. По мере прокрутки вперёд анимация тоже прокручивается. Я буду называть ихscroll-timelineанимациями, а не временными шкалами прогресса прокрутки.
Точно так же, как у нас есть два типа анимации при прокрутке, у нас есть два типаscroll-timeline-анимации:анонимные временные шкалыиименованные временные шкалы.
Давайте начнём с классического примера: создадим индикатор выполнения прокрутки в верхней части поста в блоге, чтобы отслеживать ход чтения.
Не нужно указывать секунды для продолжительности — время будет определяться поведением прокрутки. И всё! Вы только что создали свою первую анимацию, управляемую прокруткой! Обратите внимание, что направление анимации напрямую связано с направлением прокрутки: при прокрутке вниз индикатор выполнения становится шире, а при прокрутке вверх — уже.
В приведённом выше примере с чтением мы не указывали ни один из этих параметров, потому что использовали значения по умолчанию. Но мы могли бы добиться того же результата с помощью:
animation-timeline: scroll(nearest block);
Здесьnearestконтейнер прокрутки — это корневая прокрутка HTML-элемента. Таким образом, мы могли бы также написать это следующим образом:
animation-timeline: scroll(root block);
Осьblockподтверждает, что прокрутка происходит сверху вниз в режиме письма слева направо. Если страница имеет широкую горизонтальную прокрутку и мы хотим анимировать по этой оси, мы можем использовать значенияinlineилиx(в зависимости от того, хотим ли мы, чтобы направление прокрутки всегда было слева направо или менялось в зависимости от режима письма).
Мы рассмотримselfиinlineна более сложных примерах позже, но лучший способ научиться — поэкспериментировать со всеми комбинациями, иэтот инструмент позволяет вам это сделать. Прежде чем мы перейдём к следующему свойству, связанному с временными шкалами прокрутки, потратьте несколько минут на изучение.
В анимацииscroll-timelineфункцияscroll()используется внутри свойстваanimation-timeline. Она принимает только два параметра:<scroller>и<axis>.
<scroller>относится к контейнеру прокрутки, который может быть задан какnearest(по умолчанию),rootилиself.
<axis>относится к оси прокрутки, которая может бытьblock(по умолчанию),inline,x, илиy.
В приведённом выше примере с чтением мы не указывали ни один из этих параметров, потому что использовали значения по умолчанию. Но мы могли бы добиться того же результата с помощью:
Здесьnearestконтейнер прокрутки — это корневая прокрутка HTML-элемента. Таким образом, мы могли бы также написать это следующим образом:
Осьblockподтверждает, что прокрутка происходит сверху вниз в режиме письма слева направо. Если страница имеет широкую горизонтальную прокрутку и мы хотим анимировать по этой оси, мы можем использовать значенияinlineилиx(в зависимости от того, хотим ли мы, чтобы направление прокрутки всегда было слева направо или менялось в зависимости от режима письма).
Мы рассмотримselfиinlineна более сложных примерах позже, но лучший способ научиться — поэкспериментировать со всеми комбинациями.
animation-rangeСвойство
animation-rangeдляscroll-timelineопределяет, какая часть прокручиваемого содержимого управляет началом и окончанием анимации в зависимости от положения прокрутки. Это позволяет вам решать, когда анимация начинается или заканчивается при прокрутке контейнера.
По умолчаниюanimation-rangeустанавливается в значениеnormal, что является сокращением для следующего:
Это переводится как0%(start) и100%(end) вscroll-timelineанимации:
... что является таким же, как:
Вы можете указать любыеединицы измерения длины в CSSили дажевычисления. Например, предположим, что у меня есть нижний колонтитул высотой500px. Он заполнен баннерами, рекламой и связанными с ними публикациями. Я не хочу, чтобы индикатор выполнения прокрутки включал что-либо из этого в процесс чтения. Я хочу, чтобы анимация начиналась сверху и заканчивалась500pxдо нижней части. Вот и всё:
Пример временной шкалы прокрутки — animation-timeline, animation-range
Вот так просто мы рассмотрели ключевые свойстваscroll-timelineанимаций. Готовы сделать следующий шаг?
Допустим, я хочу использовать положение прокрутки другого контейнера прокрутки для той же анимации. Свойствоscroll-timeline-nameпозволяет указать, с каким контейнером прокрутки должна быть связана анимация прокрутки. Вы указываете имя (например,--my-scroll-timeline), которое соответствует контейнеру прокрутки, который вы хотите использовать. Этот контейнер будет управлять ходом анимации по мере прокрутки пользователем.
Далее нам нужно определить ось прокрутки для этого нового контейнера с помощьюscroll-timeline-axis, которая сообщает анимации, какая ось будет запускать движение. Вот как это выглядит в коде:
Если вы опустите ось, то будет использовано значениеblockпо умолчанию. Однако вы также можете использовать сокращённое свойствоscroll-timelineдля объединения имени и оси в одном объявлении:
Я думаю, что всё это проще понять на практическом примере. Вот тот же индикатор выполнения, с которым мы работали, но с встроенной прокруткой (то есть по оси X):
Смотрите именованную временную шкалу прогресса прокрутки
У нас запущены две анимации:
- Индикатор выполнения становится шире при прокрутке в направлении строки.
- Цвет фона контейнера меняется по мере дальнейшей прокрутки.
Структура HTML выглядит следующим образом:
В этом случаеgallery-scroll-containerимеет горизонтальную прокрутку и меняет цвет фона при прокрутке. Обычно для этого можно просто использоватьanimation-timeline: scroll(self inline). Однако мы также хотим, чтобы элементgallery-progressиспользовал ту же прокрутку для своей анимации.
Элементgallery-progressявляется первым внутриgallery-scroll-container, и мы потеряем его при прокрутке, если он не будет расположен абсолютно. Но когда мы это делаем, элемент больше не занимает место в обычном потоке документа, и это влияет на его взаимодействие с родительским элементом и другими элементами. Нам нужно указать, к какому контейнеру прокрутки мы хотим его привязать.
Вот где пригодится присвоение имени контейнеру прокрутки. Указавgallery-scroll-containerascroll-timeline-nameиscroll-timeline-axis, мы можем гарантировать синхронизацию обеих анимаций с одним и тем же свитком.:
И использует ли эту прокрутку для определения своей собственнойanimation-timeline:
Теперь мы можем масштабировать это название для индикатора выполнения, который использует другую анимацию, но реагирует на ту же прокрутку:
Это позволяет обеим анимациям (растущей полосе загрузки и изменению цвета фона) вести себя одинаково при прокрутке, даже если это отдельные элементы и анимации.
timeline-scopeСвойство
Что произойдёт, если мы захотим анимировать что-то в зависимости от положения прокрутки элемента-брата или даже более высокого предка? Здесь в игру вступает свойствоtimeline-scope. Оно позволяет нам расширить область действияscroll-timeline. Значениеtimeline-scope. должно быть пользовательским идентификатором, который снова является тире-идентификатором.
Давайте проиллюстрируем это на новом примере. На этот раз при прокрутке в одном контейнере запускается анимация в другом контейнере:
Анимация с прокруткой - временная шкала-область действия
Мы можем воспроизводить анимацию изображения при прокрутке текстового контейнера, потому что они являются братьями и сёстрами в структуре HTML:
Здесь только.scroll-containerимеет прокручиваемый контент, поэтому давайте начнём с его названия:
Обратите внимание, что я не указал ось прокрутки, так как по умолчанию используетсяblock(прокрутка по вертикали), и это то значение, которое мне нужно.
Давайте перейдём к изображению внутриsardinas-container. Мы хотим, чтобы это изображение анимировалось при прокруткеscroll-container. Я добавилscroll-timeline-nameк егоanimation-timelineсвойству:
Однако на этом этапе анимация всё равно не будет работать, потому чтоscroll-containerне связан напрямую с изображениями. Чтобы это работало, нам нужно расширитьscroll-timeline-nameтак, чтобы он стал доступным. Это делается путём добавленияtimeline-scopeк родительскому элементу (или более высокому предку), общему для обоих элементов:
При такой настройке прокруткаscroll-containerтеперь будет управлять анимацией изображения внутриsardinas-container!
Теперь, когда мы разобрались с использованиемtimeline-scope, мы готовы перейти к следующему типу анимации при прокрутке, где будут применяться те же свойства, но с небольшими отличиями в поведении.
Просмотр Графиков выполнения
Мы только что рассмотрелианимацию при прокрутке. Это первый тип анимации при прокрутке из двух. Далее мы обратимся канимации при просмотре. Между ними много общего! Но они достаточно отличаются друг от друга, чтобы заслуживать отдельного раздела, в котором мы рассмотрим, как они работают. Я буду называть ихview-timelineанимациями, а не анимацией при просмотре, так как они связаны сview()функцией.
Временная шкала прогресса просмотра— это второй тип анимации при прокрутке, на который мы обращаем внимание. Она отслеживает элемент, когда он входит в область прокрутки (видимую область прокручиваемого контента) или выходит из неё. Такое поведение очень похоже нато, какIntersectionObserverработает в JavaScript, но может быть реализовано полностью в CSS.
У нас есть анонимные и именованные временные шкалы прогресса просмотра, а также анонимные и именованные анимации прогресса прокрутки. Давайте разберёмся с ними.
Временная шкала Анонимного просмотра
Вот простой пример, который поможет нам понять основную идею анонимных временных шкал. Обратите внимание, как изображение появляется при прокрутке вниз до определённой точки на странице:
Смотрите анимацию View Timeline — view()
Допустим, мы хотим анимировать изображение, которое появляется в области прокрутки. Непрозрачность изображения будет меняться от0до1. Вот как можно написать эту же анимацию в классическом CSS с помощью@keyframes:
Это здорово, но мы хотим, чтобы изображениеfadeInпоявлялось, когда оно в поле зрения. В противном случае анимация будет похожа на дерево, которое падает в лесу, и никто не видит этого... была ли вообще анимация? Мы никогда не узнаем!
У нас есть функцияview()для создания анимации прогресса просмотра с помощью одной строки CSS:
И обратите внимание, что нам больше не нужно объявлятьanimation-durationкак в классическом CSS. Анимация больше не привязана ко времени, а привязана к пространству. Анимация запускается, когда изображение становится видимым в области прокрутки.
Просмотр параметров временной шкалы
Как и свойствоscroll-timeline, свойствоview-timelineпринимает параметры, которые позволяют выполнять более тонкую настройку:
<inset>
Управляет началом и окончанием анимации в зависимости от видимости элемента в области прокрутки. Определяет расстояние между краями области прокрутки и отслеживаемым элементом. Значение по умолчанию —auto, но также можно использовать процентное значение длины, а также начальное и конечное значения.
<axis>
Это похоже на параметр оси прокрутки. Он определяет, к какой оси (горизонтальной или вертикальной) привязана анимация. По умолчанию используетсяblock, что означает отслеживание вертикального движения. Вы также можете использоватьinlineдля отслеживания горизонтального движения или простоxилиy.
Вот пример, в котором используютсяinsetиaxisдля настройки времени и способа запуска анимации:
В данном случае:
- Анимация начинается, когда изображение занимает 20% видимой области прокрутки.
- Анимация запускается вертикальной прокруткой (
blockось).
Эффект параллакса
С помощью функцииview()также легко создавать эффекты параллакса, просто настраивая свойства анимации. Например, вы можете заставить элемент двигаться или масштабироваться при входе в область прокрутки без использования JavaScript:
Это невероятно упрощает создание динамичных и привлекательных анимаций прокрутки с помощью всего нескольких строк CSS.
Эффект параллакса с анимацией, управляемой прокруткой CSS - view()
animation-rangeСвойство
Использование свойства CSSanimation-rangeс временными шкалами просмотра определяет, какая часть видимости элемента в области просмотра определяет начальную и конечную точки анимации. Это можно использовать для точной настройки начала и окончания анимации в зависимости от видимости элемента в области просмотра.
Хотя значение по умолчанию равноnormal, в таймлайнах просмотра оно означает отслеживание полной видимости элемента с момента его появления в области прокрутки до полного исчезновения. Это отображается следующим образом:
Или, проще говоря:
Существует шесть возможных значений илиtimeline-range-names:
cover
Отслеживает полную видимость элемента с момента его появления в области прокрутки до момента, когда он полностью покидает её.
contain
Отслеживает, когда элемент полностью отображается в области прокрутки, с момента, когда он полностью отображается, до момента, когда он перестаёт отображаться.
entry
Отслеживает элемент с момента его появления в области прокрутки до полного заполнения области.
exit
Отслеживает элемент с момента его появления, пока он не выйдет за пределы области прокрутки.
entry-crossing
Отслеживает элемент, когда он пересекает начальную границу области прокрутки, от начала до полного пересечения.
exit-crossing
Отслеживает элемент, когда он пересекает край области прокрутки, от начала до полного пересечения.
Вы можете комбинировать различныеtimeline-range-namesдля управления начальной и конечной точками диапазона анимации. Например, вы можете сделать так, чтобы анимация начиналась, когда элемент попадает в область прокрутки, и заканчивалась, когда он из неё выходит:
Вы также можете комбинировать эти значения с процентами, чтобы задать более сложное поведение, например, начать анимацию в середине перехода элемента и завершить её в середине его выхода:
Изучать все эти значения и комбинации лучше всего в интерактивном режиме.
Дальность поражения цели Внутри@keyframes
Одной из мощных функцийtimeline-range-namesявляется возможность использовать их внутри@keyframes:
Целевой диапазон внутри @keyframes — view-timeline, timeline-range-name
В этой демо-версии происходят две разные анимации:
slideIn
Когда элемент попадает в область прокрутки, он масштабируется и становится видимым.
slideOut
Когда элемент уходит, он уменьшается в размерах и исчезает.
Новым является то, что теперь мы можем объединить эти две анимации с помощьюentryиexittimeline-range-names, упростив их до одной анимации, которая подходит для обоих случаев:
entry 0%
Определяет состояние элемента в начале его перемещения в область прокрутки (уменьшен в размере и прозрачен).
entry 100%
Определяет состояние, когда элемент полностью вошёл в область прокрутки (полностью виден и увеличен в размере).
exit 0%
Начинает отслеживать элемент, когда он начинает выходить за пределы области прокрутки (видно и увеличено).
exit 100%
Определяет состояние, когда элемент полностью покинул область прокрутки (уменьшен в размере и прозрачен).
Такой подход позволяет плавно анимировать поведение элемента при его входе в область прокрутки и выходе из неё в рамках одного блока@keyframes.
Названныйview-timelineИtimeline-scope
Концепция использованияview-timelineс именованными временными шкалами и их связывания с различными элементами может значительно расширить возможности анимации при прокрутке. В данном случае мы связываем анимацию изображений при прокрутке с анимацией несвязанных абзацев в структуре DOM с помощьюименованногоview-timelineиtimeline-scope.
Свойствоview-timelineработает так же, как и свойствоscroll-timeline. Это сокращённая запись для объявления свойствview-timeline-nameиview-timeline-axisв одной строке. Однако отличие отscroll-timelineзаключается в том, что мы можем связать анимацию элемента с моментом, когда связанные элементы попадают в область прокрутки. Я взял предыдущую демонстрацию и добавил анимацию к абзацам, чтобы вы могли увидеть, как меняется непрозрачность текста при прокрутке изображений слева:
Смотрите временную шкалу, область временной шкалы
Этот пример выглядит немного громоздким, но мне было трудно найти более подходящий для демонстрации его возможностей. Каждому изображению в контейнере с вертикальной прокруткой присваивается имяview-timelineс уникальным идентификатором:
Это позволяет присвоить временной шкале прокрутки каждого изображения собственное имя, например--oneдля первого изображения,--twoдля второго и так далее.
Далее мы подключаем анимацию абзацев к именованным временным шкалам изображений. Соответствующий абзац должен анимироваться, когда изображения попадают в область прокрутки:
Однако, поскольку изображения и абзацы не связаны напрямую в DOM, нам нужно объявитьtimeline-scopeдля их общего предка. Это гарантирует, что на именованные временные шкалы (--one,--twoи так далее) можно ссылаться и использовать их совместно между элементами:
Объявивtimeline-scopeсо всеми именованными временными шкалами (--one,—two,--three,--four), и изображения, и абзацы могут участвовать в одной и той же логике временной шкалы прокрутки, несмотря на то, что находятся в разных частях дерева DOM.
Заключение
Сегодня, в декабре 2024 года, мы рассмотрели большую часть того, что в настоящее время определено вспецификации CSS-анимации при прокрутке на уровне 1. Но я хочу выделить несколько ключевых моментов, которые помогли мне лучше понять эти новые правила, которые вы, возможно, не найдёте в спецификации напрямую:
- Предметы первой необходимости контейнера для прокрутки
Это может показаться очевидным, но для работы анимации с прокруткой необходим контейнер с прокруткой. Проблемы часто возникают при изменении размера таких элементов, как текст или контейнеры, или при тестировании анимации на больших экранах, что приводит к исчезновению области прокрутки.
- Воздействие
position: absolute
Использование абсолютного позиционирования иногда может повлиять на ожидаемое поведение анимации при прокрутке. Взаимосвязь между элементами и их родительскими элементами становится сложной, когда применяетсяposition: absolute
- Отслеживание начального состояния элемента
Браузер оценивает состояние элементадоприменения каких-либо преобразований (например,translate). Это влияет на то, когда начинается анимация, особенно на временных шкалах. Ваша анимация может запуститься раньше или позже ожидаемого времени из-за начального состояния.
- Избегайте скрытия переполнения
Использованиеoverflow: hiddenможет нарушить механизм поиска прокрутки в анимациях, управляемых прокруткой. Рекомендуемое решение — переключиться наoverflow: clip.
- Производительность
Для достижения наилучших результатов используйте для анимации свойства, оптимизированные для графического процессора, такие как преобразования, непрозрачность и некоторые фильтры. Это позволит избежать сложных вычислений компоновки и перерисовки. С другой стороны, анимация таких элементов, какwidth,height, илиbox-shadowможет замедлить работу, поскольку они требуют повторного рендеринга. Вскоре больше свойств, таких какbackground-color,clip-path,width, иheightможно будет анимировать в компоновщике, что ещё больше повысит производительность.
- Используйте
will-changeс умом
Используйте это свойство, чтобы передавать элементы на графический процессор, но применяйте его с осторожностью. Чрезмерное использованиеwill-changeможет привести к чрезмерному использованию памяти, поскольку браузер резервирует ресурсы, даже если анимация не меняется часто.
- Порядок имеет значение
Если вы используете сокращениеanimation, всегда ставьтеanimation-timelineпосле него.
- Прогрессивное усовершенствование и доступность
Объедините медиазапросы для уменьшения количества анимаций с правилом@supports, чтобы анимация применялась только в том случае, если у пользователя нет ограничений на анимацию и браузер её поддерживает.
Например:
Основная сложность, с которой я столкнулся при создании демонстраций, была связана скорее с CSS, чем с анимацией прокрутки. Иногда создать макет и сгенерировать прокрутку было сложнее, чем применить анимацию прокрутки. Кроме того, некоторые вещи, которые поначалу сбивали меня с толку, продолжают меняться, и некоторых из них больше нет (помните, что разработка ведётся уже более пяти лет!):
- оси x и y
Раньше они назывались «горизонтальной» и «вертикальной» осями, и хотя Firefox всё ещё поддерживает старую терминологию, она была обновлена.
- Старый
@scroll-timelineсинтаксис
Раньше@scroll-timelineиспользовался для объявления временных шкал прокрутки, но в последней версии спецификации это изменилось.
- Анимация, управляемая прокруткой, и анимация, связанная со прокруткой
Изначально анимации,управляемыепрокруткой, называлисьсвязаннымис прокруткой. Если вы встретите этот устаревший термин в статьях, проверьте, обновлено ли содержимое в соответствии с последней спецификацией, особенно в отношении таких функций, какtimeline-scope.