Начало работы с анимацией, управляемой прокруткой, в CSS

1. Прежде чем начать

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

Новым в Chrome 115 является поддержка набора классов JavaScript и свойств CSS, которые позволяют легко создавать декларативную анимацию, управляемую прокруткой. Эти новые API работают в сочетании с существующими API-интерфейсами веб-анимации и CSS-анимации.

В этой лаборатории кода вы узнаете, как создавать анимацию, управляемую прокруткой, с помощью CSS. Выполнив эту лабораторную работу, вы познакомитесь со многими новыми свойствами CSS, представленными этой замечательной функцией, такими как scroll-timeline , view-timeline , animation-timeline и animation-range .

Что вы узнаете

  • Как создать фоновый эффект параллакса с помощью временной шкалы прокрутки в CSS.
  • Как создать индикатор выполнения с помощью шкалы времени прокрутки в CSS.
  • Как создать эффект раскрытия изображения с помощью временной шкалы просмотра в CSS.
  • Как настроить таргетинг на различные типы диапазонов временной шкалы просмотра в CSS.

Что вам понадобится

Одна из следующих комбинаций устройств:

  • Последняя версия Chrome (115 или новее) для ChromeOS, macOS или Windows с включенным флагом «Экспериментальные функции веб-платформы».
  • Базовое понимание HTML
  • Фундаментальное понимание CSS, особенно анимации в CSS.

2. Настройте

Все, что вам нужно для этого проекта, доступно в репозитории GitHub. Для начала клонируйте код и откройте его в любимой среде разработки.

  1. Откройте новую вкладку браузера и перейдите по адресу https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab .
  2. Клонируйте репозиторий.
  3. Откройте код в предпочитаемой вами IDE.
  4. Запустите npm install , чтобы установить зависимости.
  5. Запустите npm start и посетите http://localhost:3000/ .
  6. Альтернативно, если у вас не установлен npm, откройте файл src/index.html в Chrome.

3. Узнайте о сроках анимации.

По умолчанию анимация, прикрепленная к элементу, запускается на временной шкале документа. Это означает, что когда страница загружается, анимация продвигается вперед с течением времени. Это временная шкала анимации по умолчанию, и до сих пор это была единственная временная шкала анимации, к которой у вас был доступ.

Благодаря анимации, управляемой прокруткой, вы получаете доступ к двум новым типам временных шкал:

  • Прокрутка временной шкалы прогресса
  • Посмотреть график прогресса

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

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

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

Начальная позиция прокрутки представляет прогресс 0%, а конечная позиция прокрутки представляет прогресс 100%. Обратите внимание, что на следующей визуализации прогресс увеличивается от 0% до 100% по мере прокрутки скроллера вниз.

Посмотреть график прогресса

Этот тип временной шкалы связан с относительным прогрессом конкретного элемента в контейнере прокрутки. Как и в случае с временной шкалой прогресса прокрутки, отслеживается смещение прокрутки скроллера. В отличие от временной шкалы прогресса прокрутки, прогресс определяется относительным положением объекта внутри этого скроллера. Это сравнимо с IntersectionObserver , который отслеживает, насколько элемент виден в скроллере. Если элемент не виден в скроллере, он не пересекается. Если он виден внутри скроллера – даже в самой маленькой его части – он пересекается.

Временная шкала прогресса просмотра начинается с момента, когда объект начинает пересекаться со скроллером, и заканчивается, когда объект перестает пересекать скроллер. Обратите внимание, что на следующей визуализации прогресс начинает отсчитываться от 0 %, когда субъект входит в контейнер прокрутки, и достигает 100 % к моменту выхода из контейнера прокрутки.

По умолчанию анимация, связанная с временной шкалой просмотра прогресса, прикрепляется ко всему ее диапазону. Это начинается с момента, когда субъект входит в область прокрутки, и заканчивается, когда субъект покидает область прокрутки.

Также можно связать его с определенной частью временной шкалы просмотра прогресса, указав диапазон, к которому он должен быть прикреплен. Это может быть, например, только тогда, когда субъект входит в скроллер. В следующей визуализации прогресс начинает отсчитываться от 0%, когда объект входит в контейнер прокрутки, но уже достигает 100% с момента его полного пересечения.

Возможные диапазоны просмотра временной шкалы, на которые вы можете настроить таргетинг, — это cover , contain , entry , exit , entry-crossing и exit-crossing . Эти диапазоны объяснены позже в этой лаборатории кода, но если вам не терпится узнать, воспользуйтесь инструментом, расположенным по адресу https://goo.gle/view-timeline-range-tool , чтобы увидеть, что представляет каждый диапазон.

4. Создайте фоновый эффект параллакса

Первый эффект, который нужно добавить на страницу, — это фоновый эффект параллакса на основном фоновом изображении. При прокрутке страницы вниз фоновое изображение должно двигаться, хотя и с другой скоростью. Для этого вы полагаетесь на временную шкалу прогресса прокрутки.

Для реализации этого необходимо сделать два шага:

  1. Создайте анимацию, которая перемещает положение фонового изображения.
  2. Свяжите анимацию с прогрессом прокрутки документа.

Создайте анимацию

  1. Для создания анимации используйте обычный набор ключевых кадров. В нем переместите положение фона с 0% по вертикали до 100%:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. Теперь прикрепите эти ключевые кадры к элементу body:

src/styles.css

body {
  animation: 1s linear move-background;
}

С помощью этого кода к элементу body добавляется анимация move-background . Его свойство animation-duration установлено на одну секунду и использует linear замедление.

Самый простой способ создать временную шкалу прогресса прокрутки — использовать функцию scroll() . При этом создается анонимная временная шкала прогресса прокрутки, которую можно установить в качестве значения свойства animation-timeline .

Функция scroll() принимает аргументы <scroller> и <axis> .

Допустимые значения аргумента <scroller> :

  • nearest . Использует контейнер прокрутки ближайшего предка (по умолчанию).
  • root . Использует область просмотра документа в качестве контейнера прокрутки.
  • self . Использует сам элемент в качестве контейнера прокрутки.

Допустимые значения аргумента <axis> :

  • block . Использует меру прогресса вдоль оси блока контейнера прокрутки (по умолчанию).
  • inline . Использует меру прогресса вдоль встроенной оси контейнера прокрутки.
  • y . Использует меру прогресса по оси Y контейнера прокрутки.
  • x . Использует меру прогресса по оси X контейнера прокрутки.

Чтобы связать анимацию с корневым скроллером на оси блока, в scroll() нужно передать значения root и block . В совокупности значение равно scroll(root block) .

  • Установите scroll(root block) в качестве значения свойства animation-timeline в теле.
  • Более того, поскольку animation-duration выраженная в секундах, не имеет смысла, установите для нее значение auto . Если вы не укажете animation-duration , по умолчанию будет установлено значение auto .

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

Поскольку корневой скроллер также является ближайшим родительским скроллером для элемента body, вы также можете использовать значение nearest :

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

Поскольку значения nearest и block являются значениями по умолчанию, вы можете даже опустить их. В этом случае код можно упростить до следующего:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

Подтвердите свои изменения

Если все прошло хорошо, теперь у вас должно быть следующее:

Если нет, проверьте ветку кода solution-step-1 .

5. Создайте индикатор выполнения для галереи изображений.

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

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

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

Ключевые кадры для индикатора выполнения уже установлены и выглядят следующим образом:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

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

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

Хотя может показаться, что этот фрагмент кода будет работать, это не так из-за того, что автоматический поиск контейнера прокрутки использует nearest работу. При поиске ближайшего скроллера элемент будет учитывать только те элементы, которые могут повлиять на его положение. Поскольку .gallery__progress является абсолютно позиционированным, первым родительским элементом, который будет определять его положение, является элемент .gallery , поскольку к нему применено position: relative . Это означает, что элемент .gallery__scrollcontainer , который представляет собой скроллер, на который необходимо настроить таргетинг, вообще не учитывается во время автоматического поиска.

Чтобы обойти эту проблему, создайте именованную временную шкалу прогресса прокрутки в элементе .gallery__scrollcontainer и свяжите с ней .gallery__progress , используя это имя.

Чтобы создать именованную временную шкалу прогресса прокрутки для элемента, установите для свойства CSS scroll-timeline-name в контейнере прокрутки нужное значение. Значение должно начинаться с -- .

Поскольку галерея прокручивается горизонтально, вам также необходимо установить свойство scroll-timeline-axis . Допустимые значения такие же, как и у аргумента <axis> функции scroll() .

Наконец, чтобы связать анимацию с временной шкалой выполнения прокрутки, установите для свойства animation-timeline элемента, который необходимо анимировать, то же значение, что и идентификатор, используемый для scroll-timeline-name .

  • Измените styles.css , включив в него следующее:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: --gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: --gallery-is-scrolling;
}

Подтвердите свои изменения

Если все прошло хорошо, теперь у вас должно быть следующее:

Если нет, проверьте ветку кода solution-step-2 .

6. Анимируйте изображения галереи при их входе и выходе из области прокрутки.

Настройте анонимный просмотр временной шкалы прогресса

Хороший эффект — постепенное исчезновение изображений галереи по мере их появления. Для этого вы можете использовать временную шкалу просмотра прогресса.

Чтобы создать временную шкалу просмотра прогресса, вы можете использовать функцию view() . Его приемлемыми аргументами являются <axis> и <view-timeline-inset> .

  • <axis> аналогична временной шкале прогресса прокрутки и определяет, какую ось отслеживать.
  • С помощью <view-timeline-inset> вы можете указать смещение (положительное или отрицательное), чтобы настроить границы, когда элемент считается видимым или нет.
  • Ключевые кадры уже на месте, поэтому вам нужно только прикрепить их. Для этого создайте временную шкалу просмотра прогресса для каждого элемента .gallery__entry .

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Ограничить диапазон просмотра временной шкалы прогресса

Если вы сохраните CSS и загрузите страницу, вы увидите, что элементы исчезают, но что-то кажется не так. Они начинаются с непрозрачности 0 , когда полностью находятся вне поля зрения, и заканчиваются непрозрачностью 1 только тогда, когда полностью выходят из поля зрения.

Это связано с тем, что диапазон по умолчанию для временной шкалы просмотра прогресса — полный диапазон. Это известно как диапазон cover .

  1. Чтобы настроить таргетинг только на диапазон entry объекта, используйте свойство CSS animation-range , чтобы ограничить время запуска анимации.

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

Анимация теперь выполняется от entry 0% (субъект вот-вот войдет в скроллер) до entry 100% (субъект полностью вошел в скроллер).

Возможные диапазоны просмотра временной шкалы:

  • cover . Представляет полный диапазон временной шкалы прогресса просмотра.
  • entry . Представляет диапазон, в течение которого основное поле входит в диапазон видимости прогресса просмотра.
  • exit . Представляет диапазон, в течение которого основной блок выходит из диапазона видимости прогресса просмотра.
  • entry-crossing . Представляет диапазон, в течение которого основной блок пересекает край конечной границы.
  • exit-crossing . Представляет диапазон, в течение которого основной блок пересекает границу начальной границы.
  • contain . Представляет диапазон, в течение которого основной блок либо полностью содержится, либо полностью покрывает диапазон видимости прогресса просмотра в области прокрутки. Это зависит от того, выше или короче объект скроллера.

Используйте инструмент, расположенный по адресу https://goo.gle/view-timeline-range-tool , чтобы увидеть, что представляет собой каждый диапазон и как проценты влияют на начальную и конечную позиции.

  1. Поскольку начальный и конечный диапазоны здесь одинаковы и используются смещения по умолчанию, упростите animation-range до одного имени диапазона анимации:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • Чтобы затемнить изображения при выходе из скроллера, вы можете сделать то же самое, что и при анимации, но выбрать другой диапазон.

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

Ключевые кадры animate-in будут применены к диапазону entry , а ключевые кадры animate-out — к диапазону exit .

Подтвердите свои изменения

Если все прошло хорошо, теперь у вас должно быть следующее:

Если нет, проверьте ветку кода solution-step-3 .

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

Случай для одного набора ключевых кадров

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

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

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. Объедините ключевые кадры появления и исчезновения следующим образом:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. Когда информация о диапазоне присутствует в ключевых кадрах, вам больше не нужно указывать animation-range отдельно. Прикрепите ключевые кадры как свойство animation .

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Подтвердите свои изменения

Если все прошло хорошо, вы должны получить тот же результат, что и на предыдущем шаге. Если нет, проверьте ветку кода solution-step-4 .

8. Поздравляем!

Вы завершили эту лабораторную работу и теперь знаете, как создавать временные шкалы прогресса прокрутки и просматривать временные шкалы прогресса в CSS!

Узнать больше

Ресурсы: