CSS scroll-driven animations, часть 1
Это первая часть курса по CSS Scroll-driven Animations, то есть анимациям, которые зависят от прокрутки.
Scroll-driven Animations можно использовать в Chrome версии 115 и выше, в Safari версии 26 и выше. В Firefox они поддерживаются, если включить настройку layout.css.scroll-driven-animations.enabled.
Видеоверсия этого курса доступна во ВКонтакте и на Ютюбе
Есть два типа CSS Scroll-driven Animations:
- анимации, привязанные к прогрессу прокрутки,
- анимации, привязанные к прогрессу просмотра.
В этой главе мы разберёмся, как привязывать анимации к прогрессу прокрутки.
Для начала добавим индикатор прогресса с обычной анимацией, которая повторяется бесконечно.
Подготовимся к подключению анимации прокрутки и её тестированию.
Добавим кнопки для прокрутки экрана в разные положения и по умолчанию прокрутим экран к середине.
Вы можете покликать по кнопкам и проверить, как они работают.
Удалим у анимации длительность и количество повторений. Эти параметры не нужны для анимаций, привязанных к прокрутке. Анимация индикатора остановится.
Мы находимся в середине экрана, поэтому при включении анимации прокрутки индикатор должен закраситься ровно наполовину.
Добавим всего одно свойство — animation-timeline со значением scroll().
Вот и всё! Мы создали нашу первую анимацию, которая зависит от прокрутки.
Включим режим плавной прокрутки и прокрутим мини-браузер в самый низ. Индикатор должен закраситься полностью. Работает!
Теперь понажимайте кнопки по очереди или прокрутите страницу и посмотрите, как ведёт себя анимируемый элемент.
Обратите внимание, что направление анимации связано с направлением прокрутки: при прокрутке страницы вниз индикатор прогресса уменьшается, а при прокрутке вверх — увеличивается.
CSS-свойство animation-timing-function отлично работает со скролл-анимациями.
Давайте изменим значение этого свойства на ease-in и установим прокрутку по центру. Значение в прогрессбаре — 120deg.
Теперь, не изменяя положение прокрутки, установим значение animation-timing-function равным linear. Индикатор обновился! Теперь его значение — 180deg.
Используем сложную функцию linear(). Прокрутите скроллбар самостоятельно сверху вниз и посмотрите, как ведёт себя индикатор.
Чтобы анимация прогресса прокрутки работала, необходим контейнер с прокруткой. В нашем случае это весь документ.
Если прокрутки нет, анимация не будет работать.
Мы уменьшили содержимое страницы, и скролл исчез. Теперь анимация не запускается.
Давайте добавим больше блоков, но ограничим высоту блока .main-container. Одновременно зададим ему overflow: hidden. Прокрутки нет, анимации тоже.
Удалим ограничение высоты и overflow: hidden. Прокрутка вернулась, анимация заработала.
CSS-свойство animation-timeline не входит в сокращённую запись animation, но его значение сбрасывается при её использовании. То же самое происходит с background-color при использовании сокращённой записи background.
Зададим animation-timeline перед animation. Анимация не работает.
CSS-свойство animation-timeline нужно объявлять после animation:
/* Неправильный порядок CSS-свойств */
animation-timeline: scroll();
animation: progress linear;
/* Правильный порядок CSS-свойств */
animation: progress linear;
animation-timeline: scroll();
Функция scroll() создаёт анонимную временную шкалу прокрутки.
Давайте подробнее рассмотрим параметры этой функции.
Функция scroll() принимает два параметра: <scroller> и <axis>.
Параметр <scroller> задаёт элемент со скроллом или «скроллер», к состоянию которого привязывается анимация. У параметра три значения: nearest (значение по умолчанию), root или self.
Параметр <axis> задаёт ось прокрутки, к которой привязывается анимация. У параметра четыре значения: block (значение по умолчанию), inline, x или y.
Давайте разберёмся, как работает значение nearest параметра <scroller>. На первый взгляд, всё просто — анимация привязывается к ближайшему предку, который является скролл-контейнером.
С помощью vh добьёмся, чтобы на странице появилось две полосы прокрутки: одна у элемента .main-container, другая у корневого элемента.
Прокрутите обе полосы. Анимация индикатора привязалась к корневому элементу. Как так?!
Всё вроде бы правильно: мы анимируем .progress, который находится внутри .main-container. У .main-container есть полоса прокрутки, значит, он и должен быть «ближайшим скролл-контейнером». Но почему-то анимация привязывается к полосе прокрутки страницы.
Может быть, проблема в position: fixed у индикатора? Заменим значение CSS-свойства position на absolute. Нет, это не помогает.
Теперь зададим для .main-container относительное позиционирование (position: relative;). Анимация скролла заработала, как ожидалось. Всё дело в концепции Containing Block для позиционированных элементов, который не всегда совпадает с родителем в DOM-дереве.
Совет: для скролл-анимаций вложенных скролл-контейнеров лучше использовать именованную временную шкалу прокрутки. Мы разберём её позже.
Теперь изменим значение параметра <scroller> на root. Анимация индикатора привязалась к прокрутке страницы, хотя индикатор находится внутри блока с собственным скроллом.
Подвигайте скроллбары и убедитесь в этом.
Подведём итог различий между nearest и root. Значение nearest связывает анимацию с ближайшим скролл-контейнером (и поиск «ближайшего скролл-контейнера» может преподнести сюрпризы). Значение root связывает анимацию с корневым скролл-контейнером.
Осталось третье значение — self.
С помощью self анимацию прокрутки можно привязать к состоянию прокрутки самого элемента.
Добавим на страницу три элемента, ограничим их по высоте и наполним содержимым так, чтобы появилась полоса прокрутки.
Теперь анимируем цвет фона самих элементов в зависимости от их собственных полос прокрутки с помощью scroll(self). У self, как и у root, никаких сюрпризов с определением скролл-контейнера не возникает.
Прокрутите элементы и посмотрите, как их фон меняется.
Мы разобрали все значения параметра <scroller>, теперь познакомимся с параметром <axis>.
Значение по умолчанию block привязывает анимацию к вертикальной прокрутке. Направление может меняться в зависимости от направления текста (CSS-свойство writing-mode).
Значение y привязывает анимацию к вертикальной полосе прокрутки.
Изменим контейнеры так, чтобы в них появилась горизонтальная полоса прокрутки.
Как видите, анимация перестала работать.
Чтобы «починить» анимацию, меняем значение <axis> на inline. Анимация привязалась к горизонтальной полосе прокрутки и снова заработала.
При значении inline браузер использует горизонтальную прокрутку. Направление также может меняться в зависимости от направления текста.
Значение x привязывает анимацию к горизонтальной полосе прокрутки.
Мы рассмотрели основные возможности анонимной временной шкалы прокрутки. До встречи в следующей части!