Pull to refresh
89.56
Skillfactory
Онлайн-школа IT-профессий

Анимация при прокрутке с помощью WAAPI и ScrollTimeline

Reading time6 min
Views12K
Original author: Bramus

Спецификация W3C Scroll-linked Animations — это экспериментальное дополнение, которое позволяет связать развитие эффекта анимации с прокруткой. Подробностями делимся под катом, пока у нас начинается курс по Frontend-разработке.


В предыдущем материале на CSS-Tricks мы рассмотрели несколько примеров использования, все они были созданы с помощью CSS @scroll-timeline at-rule и свойства animation-timeline, которые предоставляет спецификация. Все эти примеры созданы только с помощью HTML и CSS. Никакого JavaScript.

Помимо интерфейса CSS, получаемого с помощью спецификации Scroll-linked Animations, она также описывает интерфейс JavaScript для реализации анимации с прокруткой. Рассмотрим класс ScrollTimeline и то, как использовать его с WAAPI.

Краткий обзор WAAPI

WAAPI на CSS-Tricks уже рассматривался. Напомним: API позволяет создавать анимацию и управлять её воспроизведением с помощью JavaScript. Возьмём следующую анимацию на CSS. В верхней части страницы расположена полоса. Она анимируется:

  1. с красного цвета на тёмно-красный;

  2. масштабированием оси x — от нулевой ширины до ширины в 100 %.

Если переписать анимацию на WAAPI, код станет таким:

new Animation(
  new KeyframeEffect(
    document.querySelector('.progressbar'),
    {
      backgroundColor: ['red', 'darkred'],
      transform: ['scaleX(0)', 'scaleX(1)'],
    },
    {
      duration: 2500,
      fill: 'forwards',
      easing: 'linear',
    }
  )
).play();

Можно воспользоваться коротким синтаксисом с Element.animate():

document.querySelector('.progressbar').animate(
  {
    backgroundColor: ['red', 'darkred'],
    transform: ['scaleX(0)', 'scaleX(1)'],
  },
  {
    duration: 2500,
    fill: 'forwards',
    easing: 'linear',
   }
);

В двух последних примерах JavaScript можно выделить две вещи. Во-первых, объект keyframes. Этот объект описывает, какие свойства анимируются:

{
  backgroundColor: ['red', 'darkred'],
  transform: ['scaleX(0)', 'scaleX(1)'],
}

Второй — это объект опций options, настраивающий продолжительность анимации, сглаживание и так далее:

{
  duration: 2500,
  fill: 'forwards',
  easing: 'linear',
}

Пишем и подключаем ScrollTimeline

Чтобы анимация управлялась не монотонными часами, а прокруткой, мы можем сохранить существующий код WAAPI, но должны дописать его, подключив к нему экземпляр ScrollTimeline.

Этот класс позволяет нам описать AnimationTimeline, значения времени которого определяются не временем часов, а прогрессом прокрутки в контейнере. Его можно настроить с помощью нескольких параметров. О них подробнее — ниже.

  • source: прокручиваемый элемент, прокрутка которого вызывает активацию и управляет прогрессом временной шкалы. По умолчанию это document.scrollingElement (т.е. контейнер прокрутки, который прокручивает весь документ).

  • orientation: определяет направление прокрутки, которое запускает активацию временной шкалы и управляет её ходом. По умолчанию ориентация вертикальная (или block как логическое значение).

  • scrollOffsets: определяют эффективные смещения прокрутки, которые перемещаются в заданном ориентацией направлении. Они представляют собой равномерно распределённые по времени интервалы, где активна временная шкала.

Эти параметры передаются в конструктор. Например:

const myScrollTimeline = new ScrollTimeline({
  source: document.scrollingElement,
  orientation: 'block',
  scrollOffsets: [
    new CSSUnitValue(0, 'percent'),
    new CSSUnitValue(100, 'percent'),
  ],
});

Они полностью совпадают с дескрипторами CSS @scroll-timeline. Это не случайно. Оба подхода позволяют достичь одного и того же результата, разница состоит в языке определения.

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

Когда работаете с Element.animate(), установите его параметром временной шкалы объекта options:

document.querySelector("#progress").animate(
  {
    transform: ["scaleX(0)", "scaleX(1)"]
  },
  { 
    duration: 1, 
    fill: "forwards", 
    timeline: myScrollTimeline
  }
);

С помощью этого кода анимация управляется экземпляром ScrollTimeline, а не стандартным DocumentTimeline. Текущая, экспериментальная реализация в Chromium, работает со scrollSource, а не source. Поэтому в примерах кода видно и source, и scrollSource.

Несколько слов о кроссбраузерности

На момент написания статьи только браузеры Chromium поддерживают класс ScrollTimeline, при этом нужно включить соответствующий флаг.

К счастью, есть полифилл Scroll-Timeline Polyfill. Его можно использовать для компенсации неподдерживаемых функций во всех остальных браузерах. Все демо из этой статьи используют этот полифилл. Он доступен как модуль и, если не обнаружено никакой поддержки нужной функциональности, он регистрируется самостоятельно. Чтобы включить его, добавьте в свой код такой import:

import 'https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js';

Полифилл также регистрирует необходимые классы CSS Typed Object Model, если браузер их не поддерживает (ждём тебя, Safari).

Продвинутые анимации ScrollTimeline

Помимо абсолютных смещений анимация с прокруткой может работать со смещениями на основе элементов.

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

Смещение на основе элемента описывается тремя аргументами. Это:

  1. Отслеживаемый элемент DOM — target.

  2. Элемент, за пересечением которого следит ScrollTimeline source, — edge.

  3. Число в диапазоне от 0,0 до 1,0. Оно указывает, какая часть элемента видна в порте прокрутки у края и называется threshold. Вы можете узнать об этом от IntersectionObserver. И вот что мы увидим:

Если вы хотите узнать больше о смещениях на основе элементов, включая принцип их работы и примеры часто используемых смещений, ознакомьтесь с этой статьёй. Смещение на основе элементов поддерживается интерфейсом JS ScrollTimeline. Чтобы определить интерфейс, используйте привычный объект, как ниже:

{
  target: document.querySelector('#targetEl'),
  edge: 'end',
  threshold: 0.5,
}

Обычно в свойство scrollOffsets передаются два таких объекта:

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 },
      ],
    }),
  }
);

Этот код задействован в примере ниже. Вы видите JavaScript-ремейк эффекта, который я рассматривал в прошлый раз: изображение проявляется при прокрутке в область просмотра.

Горизонтальная секция прокрутки

Этот пример на основе демо Камерона Найта, где есть секция с горизонтальной прокруткой. Он ведёт себя так же, но вместо GSAP ScrollTrigger использует ScrollTimeline.

Чтобы узнать больше о том, как работает этот код, и увидеть версию на чистом CSS, обратитесь к этой статье.

CoverFlow

Помните CoverFlow из iTunes? Вот созданная при помощи ScrollTimeline версия этого эффекта:

Демонстрация не работает на 100 % так, как ожидается в Chromium, из-за бага. Проблема заключается в неверном расчёте начальной и конечной позиций. Объяснение с видео вы можете найти здесь.

Подробнее о примере читайте здесь.

CSS или JavaSript?

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

  • Chromium поддерживает её, если включить соответствующий флаг в chrome://flags.

  • Firefox готовит наработки: Mozilla Ticket #1676780.

  • От Safari пока ничего не слышно: WebKit Ticket #222295.

Из-за такой слабой поддержки, вы, конечно, можете писать на JavaScript. Просто убедитесь, что с сайтом можно работать и при отключенном JavaScript. Продолжить изучение возможностей CSS и других технологий фронтенда вы сможете на наших курсах:

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

Профессии и курсы
Tags:
Hubs:
+4
Comments0

Articles

Information

Website
www.skillfactory.ru
Registered
Founded
Employees
501–1,000 employees
Location
Россия
Representative
Skillfactory School