От автора: спецификация Scroll-linked Animations — это предстоящее и экспериментальное дополнение, которое позволяет нам связывать анимацию с прокруткой: когда вы прокручиваете вверх и вниз контейнер прокрутки, связанный элемент также продвигается или перематывается соответственно.
Мы рассмотрели некоторые варианты использования в предыдущем разделе, посвященном CSS-трюкам, все они управляются правилом CSS @scroll-timeline и свойством animation-timeline, эти варианты использования были созданы с использованием только HTML и CSS. Без JavaScript.
Помимо интерфейса CSS, который мы получаем со спецификацией scroll-connected Animations, в ней также описан интерфейс JavaScript для реализации scroll-linked анимаций. Давайте рассмотрим класс ScrollTimeline и то, как его использовать с API веб-анимации.
API веб-анимации: краткое резюме
API веб-анимации (WAAPI) уже рассматривался в CSS-Tricks. Вкратце, этот API позволяет нам создавать анимации и управлять их воспроизведением с помощью JavaScript. Возьмем, к примеру, следующую CSS-анимацию, в которой полоса находится вверху страницы, и:
Изменяет цвет от красного до темно-красного
Изменяет ширину от нуля до полной ширины контейнера (путем масштабирования оси x).
При переводе анимации CSS в ее аналог WAAPI код становится следующим:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
new Animation( new KeyframeEffect( document.querySelector('.progressbar'), { backgroundColor: ['red', 'darkred'], transform: ['scaleX(0)', 'scaleX(1)'], }, { duration: 2500, fill: 'forwards', easing: 'linear', } ) ).play(); |
Или, в качестве альтернативы, используйте более краткий синтаксис с использованием Element.animate():
1 2 3 4 5 6 7 8 9 10 11 |
document.querySelector('.progressbar').animate( { backgroundColor: ['red', 'darkred'], transform: ['scaleX(0)', 'scaleX(1)'], }, { duration: 2500, fill: 'forwards', easing: 'linear', } ); |
В двух последних примерах мы можем выделить две вещи. Во-первых — объект, описывающий, какие свойства нужно анимировать:
1 2 3 4 |
{ backgroundColor: ['red', 'darkred'], transform: ['scaleX(0)', 'scaleX(1)'], } |
Во-вторых – объект, который настраивает продолжительность анимации, замедление и т. д.:
1 2 3 4 5 |
{ duration: 2500, fill: 'forwards', easing: 'linear', } |
Создание и прикрепление шкалы времени прокрутки
Чтобы анимация управлялась с помощью прокрутки, мы можем сохранить существующий код WAAPI, но необходимо расширить его, добавив к нему экземпляр класса ScrollTimeline.
Класс ScrollTimeline позволяет нам описывать AnimationTimeline, чьи значения времени определяются не продолжительностью времени, а прогрессом прокрутки в контейнере прокрутки. Его можно настроить с помощью нескольких опций:
source: Прокручиваемый элемент, прокрутка которого запускает активацию и управляет прогрессом временной шкалы. По умолчанию это document.scrollingElement (т. е. Контейнер прокрутки, который прокручивает весь документ).
orientation: Определяет направление прокрутки, которое запускает активацию и управляет прогрессом временной шкалы. По умолчанию равно vertical.
scrollOffsets: Значения, которые определяет эффективное смещение прокрутки, перемещаясь в направлении, указанном в свойстве orientation. Они представляют собой равноудаленные по ходу выполнения интервалы, в которых активна временная шкала.
Эти параметры передаются в конструктор. Например:
1 2 3 4 5 6 7 8 |
const myScrollTimeline = new ScrollTimeline({ source: document.scrollingElement, orientation: 'block', scrollOffsets: [ new CSSUnitValue(0, 'percent'), new CSSUnitValue(100, 'percent'), ], }); |
Не случайно эти параметры в точности совпадают с дескрипторами CSS @scroll-timeline. Оба подхода позволяют достичь одного и того же результата, разница лишь в использовании языка для их определения.
Чтобы добавить вновь созданный экземпляр ScrollTimeline к анимации, мы передаем его в качестве второго аргумента в конструктор Animation:
1 2 3 4 5 6 7 8 |
new Animation( new KeyframeEffect( document.querySelector('#progress'), { transform: ['scaleX(0)', 'scaleX(1)'], }, { duration: 1, fill: 'forwards' } ), myScrollTimeline ).play(); |
При использовании синтаксиса Element.animate() установите его как параметр timeline:
1 2 3 4 5 6 7 8 9 10 |
document.querySelector("#progress").animate( { transform: ["scaleX(0)", "scaleX(1)"] }, { duration: 1, fill: "forwards", timeline: myScrollTimeline } ); |
С этим кодом анимация управляется нашим экземпляром ScrollTimelin, а не DocumentTimeline. Текущая экспериментальная реализация в Chromium использует scrollSource вместо source. Вот почему вы видите и source и scrollSource в примерах кода.
Несколько слов о совместимости браузеров
На момент написания статьи только браузер Chromium поддерживает класс ScrollTimeline. К счастью, есть полифил Scroll-Timeline от Роберта Флэка, который мы можем использовать для заполнения неподдерживаемых пробелов во всех других браузерах. Фактически, все демонстрации в этой статье, включают его.
Полифилл доступен в виде модуля и регистрирует себя, если поддержка не обнаружена. Чтобы включить его, добавьте в секцию import своего кода следующий оператор:
1 |
import 'https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js'; |
Полифилл также регистрирует необходимые классы типизированной объектной модели CSS, если браузер не поддерживает их.
Продвинутая временная шкала прокрутки
Помимо абсолютных смещений, scroll-linked анимация также может работать со смещениями на основе элементов. С этим типом смещения, анимация основана на расположении элемента в контейнере прокрутки. Обычно это используется для анимации элемента, когда он входит в область прокрутки, пока он не покинет ее.
Смещение на основе элементов состоит из трех частей:
target: Отслеживаемый элемент DOM.
edge: То, за чем наблюдает ScrollTimeline.
threshold: Число в диапазоне от 0.0 до 1.0 которое указывает, какая часть target видна в области прокрутки edge.
Смещения на основе элементов также поддерживаются интерфейсом ScrollTimeline. Чтобы определить его, используйте обычный объект:
1 2 3 4 5 |
{ target: document.querySelector('#targetEl'), edge: 'end', threshold: 0.5, } |
Обычно в свойство scrollOffsets передаются два из этих объектов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const $image = document.querySelector('#myImage'); $image.animate( { opacity: [0, 1], clipPath: ['inset(45% 20% 45% 20%)', 'inset(0% 0% 0% 0%)'], }, { duration: 1, fill: "both", timeline: new ScrollTimeline({ scrollSource: document.scrollingElement, timeRange: 1, fill: "both", scrollOffsets: [ { target: $image, edge: 'end', threshold: 0.5 }, { target: $image, edge: 'end', threshold: 1 }, ], }), } ); |
Вот еще несколько примеров, которые я приготовил.
Секция горизонтальной прокрутки
Пример основан на демонстрации Кэмерона Найта, в которой есть секция горизонтальной прокрутки. Она ведет себя аналогично, но использует ScrollTimeline вместо GSAP ScrollTrigger.
CoverFlow
Помните CoverFlow из iTunes? Что ж, вот версия, построенная на ScrollTimeline:
Эта демонстрация не работает должным образом в Chromium из-за ошибки. Проблема в том, что начальная и конечная позиции рассчитываются неправильно.
CSS или JavaScript?
Нет никакой реальной разницы в использовании CSS или JavaScript для Scroll-linked анимаций, за исключением используемого языка: оба используют одни и те же концепции и конструкции. В духе прогрессивного улучшения я бы выбрал CSS для такого рода эффектов.
Однако, как мы уже говорили ранее, поддержка реализации на основе CSS на момент написания статьи была довольно слабой:
Chromium имеет только экспериментальную реализацию.
Firefox только готовится для внедрения реализации на основе CSS.
Никаких сообщений от Safari пока нет.
Из-за этой плохой поддержки вы наверняка достигнете успеха с JavaScript прямо сейчас. Просто убедитесь, что ваш сайт можно просматривать и использовать при отключенном JavaScript.
Автор: Bramus
Источник: css-tricks.com
Редакция: Команда webformyself.
Читайте нас в Telegram, VK, Яндекс.Дзен