Как NRK использует анимацию, управляемую прокруткой, чтобы оживить истории,Как NRK использует анимацию, управляемую прокруткой, чтобы оживить истории

Опубликовано: 26 февраля 2026 г.

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

НРК и рассказывание историй

NRK (Норвежская радиовещательная корпорация) — общественная вещательная компания Норвегии . Команда, стоящая за реализацией, описанной в этой статье, по-норвежски называется Visuelle Historier, что примерно переводится как «Визуальные истории» на английском языке. Команда занимается дизайном, графикой и разработкой редакционных проектов для телевидения, радио и Интернета, разрабатывая визуальную идентичность, графику контента, тематические статьи и новые форматы визуального повествования. Команда также работает с профилем дизайна и суббрендами NRK, создавая инструменты и шаблоны, упрощающие публикацию контента в соответствии с фирменным стилем NRK.

Как NRK использует анимацию, управляемую прокруткой

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

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

Улучшение пользовательского опыта

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

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

Создание настроения

Анимация может быть мощным инструментом для создания или улучшения настроения истории. Регулируя время, скорость и стиль анимации, NRK может вызывать эмоции, соответствующие тону повествования.

Разбейте текст и обеспечьте визуальное облегчение

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

Уважение потребностей в доступности и предпочтений пользователей

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

Разработка анимации, управляемой прокруткой.

NRK оптимизировала рабочий процесс проектирования, разработав и интегрировав новый инструмент анимации прокрутки непосредственно в свою систему управления контентом Sanity (CMS). Этот инструмент, разработанный в сотрудничестве между командами, которые разрабатывают и поддерживают сайт, и решениями CMS, позволяет дизайнерам легко создавать прототипы и реализовывать анимацию прокрутки с визуальными подсказками для начальной и конечной позиции анимированного элемента, а также возможностью предварительного просмотра анимации в режиме реального времени. Это нововведение дает дизайнерам больший контроль и ускоряет процесс проектирования непосредственно в CMS.

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

Анимация, управляемая прокруткой, в браузере

Сюжетная анимация

Человек, которого не пропустили .

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

Анимация затухания текста

Вечная мерзлота .

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

.article-section {
  animation: fade-up linear;
  animation-timeline: view();
  animation-range: entry 100% exit 100%;
}

Анимированная типографика с прокруткой

Анимированная типографика в заголовке статьи — Больничный .

Введением в «Sjukt sjuke» (что примерно переводится как «болезненный больной») NRK хотела привлечь читателей к статье о росте количества отпусков по болезни в Норвегии. Название должно было визуально привлекать внимание и давать читателям намек на то, что это не обычная, скучная история, основанная на цифрах, которую они могли ожидать. Команда NRK хотела, чтобы текст и иллюстрации соответствовали темам произведения, используя для этого типографику и анимацию, управляемую прокруткой. В статье используется новый шрифт и профиль дизайна NRK News.

<h1 aria-label="sjuke">
  <span>s</span><span>j</span><span>u</span><span>k</span><span>e</span>
<h1>
h1 span {
  display: inline-block;
}
if (window.matchMedia('print, (prefers-reduced-motion: reduce)').matches) {
  return;
}

const heading = document.querySelector("h1");
const letters = heading.querySelectorAll("span");

const timeline = new ViewTimeline({ subject: heading });
const scales = [/**/];
const rotations = [/**/];

for ([index, el] of letters.entries()) {
  el.animate(
    {
      scale: ["1", scales[index]],
      rotate: ["0deg", rotations[index]]
    },
    {
      timeline,
      fill: "both",
      rangeStart: "contain 30%",
      rangeEnd: "contain 70%",
      easing: "ease-out"
    }
  );
}

Выделение элементов, привязанных к прокрутке

Дети в учреждениях .

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

for (let item of items) {
  const timeline = new ViewTimeline({ subject: item, axis: "inline" });
  const animation = new Animation(effect, timeline);
  item.animate(
    {
      opacity: [0.3, 1, 0.3]
    },
    { timeline, easing: "ease-in-out", fill: "both" }
  );
  animation.rangeStart = "cover calc(50% - 100px)";
  animation.rangeEnd = "cover calc(50% + 100px)";
}

Анимация прокрутки, запускающая обычную анимацию

Бюджет .

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

const timeline = new ViewTimeline({
  subject: containerElement
});

// Setup scroll-driven animation
const scrollAnimation = containerElement.animate(
  {
    "--cover-color": ["blue", "lightblue"],
    scale: ["1 0.2", "1 3"]
  },
  {
    timeline,
    easing: "cubic-bezier(1, 0, 0, 0)",
    rangeStart: "cover 0%",
    rangeEnd: "cover 50%"
  }
);

// Wait for scroll-driven animation to complete
await scrollAnimation.finished;
scrollAnimation.cancel();

// Trigger time-driven animations
for (let [index, postElement] of postElements.entries()) {
  const animation = postElement?.animate(
    { scale: ["1 3", "1 1"] },
    {
      duration: 200,
      delay: index * 33,
      easing: "ease-out",
      fill: "backwards"
    }
  );
}

«Мы занимались анимацией, управляемой прокруткой, в течение долгого времени. До появления API веб-анимации нам приходилось использовать события прокрутки, которые позже объединялись с API Intersection Observer API. Часто это была очень трудоемкая задача, а теперь это стало тривиальным благодаря API веб-анимации и анимации, управляемой прокруткой», — Хельге Силсет, фронтенд-разработчик в NRK

NRK имеет множество различных веб-компонентов , которые можно подключить к одному из их пользовательских элементов, называемому ScrollAnimationDriver ( <scroll-animation-driver> ), поддерживающему следующие анимации:

  • Слои с [KeyframeEffects](https://developer.mozilla.org/docs/Web/API/KeyframeEffect)
  • Лотти анимации
  • mp4
  • три.js
  • <canvas>

В следующем примере используются слои с KeyframeEffects :

<scroll-animation-driver data-range-start='entry-crossing 50%' data-range-end='exit-crossing 50%'>
  <layered-animation-effect>
    <picture>
      <source />
      <img />
    </picture>

    <picture>
      <source />
      <img />
    </picture>

    <picture>
      <source />
      <img />
    </picture>
  </layered-animation-effect>
</scroll-animation-driver>

JavaScript-реализация NRK пользовательского элемента <scroll-animation-driver> :

export default class ScrollAnimationDriver extends HTMLElement {
  #timeline

  connectedCallback() {
    this.#timeline = new ViewTimeline({subject: this})
    for (const child of this.children) {
      for (const effect of child.effects ?? []) {
        this.#setupAnimationEffect(effect)
      }
    }
  }

  #setupAnimationEffect(effect) {
    const animation = new Animation(effect, this.#timeline) 
    animation.rangeStart = this.rangeStart
    animation.rangeEnd = this.rangeEnd

    if (this.prefersReducedMotion) {
      animation.currentTime = CSS.percent(this.defaultProgress * 100)
    } else {
      animation.play()
    }
  }
}

export default class LayeredAnimationEffect extends HTMLElement {
  get effects() {
    return this.layers.flatMap(layer => toKeyframeEffects(layer))
  }
}

Производительность прокрутки

До того, как стали использовать анимацию, управляемую прокруткой, у NRK была очень производительная реализация JavaScript, но теперь анимация, управляемая прокруткой, позволяет им иметь еще лучшую производительность, не беспокоясь о зависаниях при прокрутке, даже на маломощных устройствах.

  • Длительность задачи без SDA: 1 мс.
  • Длительность задачи SDA: 0,16 мс.
Вкладка «Производительность» Chrome DevTools.
Запись на вкладке «Производительность» Chrome DevTools с замедлением ЦП в 6 раз показывает 0,16 мс для каждой задачи в новом кадре.

Чтобы узнать больше о разнице в производительности прокрутки между реализациями JavaScript и анимацией, управляемой прокруткой, более подробно рассматривается статья Пример использования анимации, управляемой прокруткой .

Вопросы доступности и UX

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

  • Уважение предпочтений пользователя в отношении уменьшения движения : использование screen and (prefers-reduced-motion: no-preference) для применения анимации в качестве постепенного улучшения. Также полезно одновременно обрабатывать стили печати.
  • Учитывая широкий спектр устройств и разную точность ввода при прокрутке : некоторые пользователи могут прокручивать пошагово (пробел или клавиши вверх/вниз, переход к ориентирам с помощью программы чтения с экрана) и не видеть всю анимацию. Убедитесь, что важная информация не пропущена.
  • Будьте осторожны с анимацией, показывающей или скрывающей контент . Пользователям, использующим масштабирование операционной системы (ОС), может быть трудно заметить, что скрытый контент появляется при прокрутке. Не заставляйте пользователей искать его. Если необходимо скрыть или показать контент, убедитесь, что он появляется и исчезает.
  • Избегайте больших изменений яркости или контрастности анимации . Поскольку анимация, управляемая прокруткой, зависит от контроля пользователя, резкие изменения яркости могут проявляться в виде мигания, что может вызвать судороги у некоторых пользователей.
@media (prefers-reduced-motion: no-preference) {
  .article-image {
    opacity: 0;
    transition: opacity 1s ease-in-out;
  }
  .article-image.visible {
    opacity: 1;
  }
}

Поддержка браузера

Для более широкой поддержки браузерами ScrollTimeline и ViewTimeline NRK использует полифил с открытым исходным кодом , в который вносит свой вклад активное сообщество .

В настоящее время полифил загружается условно, когда ScrollTimeline недоступен, и используется урезанная версия полифила без поддержки CSS.

if (!('ScrollTimeline' in window)) {
  await import('scroll-timeline.js')
}

Обнаружение и обработка поддержки браузера в CSS:

@supports not (animation-timeline: view()) {
  .article-section {
    translate: 0 calc(-15vh * var(--fallback-progress));
    opacity: var(--fallback-progress);
  }
}

@supports (animation-timeline: view()) {
  .article-section {
    animation: --fade-up linear;
    animation-timeline: view();
    animation-range: entry 100% exit 100%;
  }
}

В предыдущем примере для неподдерживаемых браузеров NRK использует переменную CSS --fallback-progress в качестве резерва для управления временной шкалой анимации для свойств translate и opacity .

Затем переменная CSS --fallback-progress обновляется с помощью прослушивателя событий scroll и requestAnimationFrame в JavaScript следующим образом:

function updateProgress() {
  const end = el.offsetTop + el.offsetHeight;
  const start = end - window.innerHeight;
  const scrollTop = document.scrollingElement.scrollTop;
  const progress = (scrollTop - start) / (end - start);
  document.body.style.setProperty('--fallback-progress', clamp(progress, 0, 1));
}


if (!CSS.supports("animation-timeline: view()")) {
  document.addEventListener('scroll', () => {
    if (!visible || updating) {
      return;
    }

    window.requestAnimationFrame(() => {
      updateProgress();
      updating = false;
    });

    updating = true;
  });
}

Ресурсы

Особая благодарность Ханне Ван Опстал, Брамусу и Эндрю Кину Гуану из Google, а также Ингрид Рейме из NRK за их ценный вклад в эту работу.

,

Опубликовано: 26 февраля 2026 г.

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

НРК и рассказывание историй

NRK (Норвежская радиовещательная корпорация) — общественная вещательная компания Норвегии . Команда, стоящая за реализацией, описанной в этой статье, по-норвежски называется Visuelle Historier, что примерно переводится как «Визуальные истории» на английском языке. Команда занимается дизайном, графикой и разработкой редакционных проектов для телевидения, радио и Интернета, разрабатывая визуальную идентичность, графику контента, тематические статьи и новые форматы визуального повествования. Команда также работает с профилем дизайна и суббрендами NRK, создавая инструменты и шаблоны, упрощающие публикацию контента в соответствии с фирменным стилем NRK.

Как NRK использует анимацию, управляемую прокруткой

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

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

Улучшение пользовательского опыта

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

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

Создание настроения

Анимация может быть мощным инструментом для создания или улучшения настроения истории. Регулируя время, скорость и стиль анимации, NRK может вызывать эмоции, соответствующие тону повествования.

Разбейте текст и обеспечьте визуальное облегчение

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

Уважение потребностей в доступности и предпочтений пользователей.

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

Разработка анимации, управляемой прокруткой.

NRK оптимизировала рабочий процесс проектирования, разработав и интегрировав новый инструмент анимации прокрутки непосредственно в свою систему управления контентом Sanity (CMS). Этот инструмент, разработанный в сотрудничестве между командами, которые разрабатывают и поддерживают сайт, и решениями CMS, позволяет дизайнерам легко создавать прототипы и реализовывать анимацию прокрутки с визуальными подсказками для начальной и конечной позиции анимированного элемента, а также возможностью предварительного просмотра анимации в режиме реального времени. Это нововведение дает дизайнерам больший контроль и ускоряет процесс проектирования непосредственно в CMS.

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

Анимация, управляемая прокруткой, в браузере

Сюжетная анимация

Человек, которого не пропустили .

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

Анимация затухания текста

Вечная мерзлота .

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

.article-section {
  animation: fade-up linear;
  animation-timeline: view();
  animation-range: entry 100% exit 100%;
}

Анимированная типографика с прокруткой

Анимированная типографика в заголовке статьи — Больничный .

Введением в «Sjukt sjuke» (что примерно переводится как «болезненный больной») NRK хотела привлечь читателей к статье о росте количества отпусков по болезни в Норвегии. Название должно было визуально привлекать внимание и давать читателям намек на то, что это не обычная, скучная история, основанная на цифрах, которую они могли ожидать. Команда NRK хотела, чтобы текст и иллюстрации соответствовали темам произведения, используя для этого типографику и анимацию, управляемую прокруткой. В статье используется новый шрифт и профиль дизайна NRK News.

<h1 aria-label="sjuke">
  <span>s</span><span>j</span><span>u</span><span>k</span><span>e</span>
<h1>
h1 span {
  display: inline-block;
}
if (window.matchMedia('print, (prefers-reduced-motion: reduce)').matches) {
  return;
}

const heading = document.querySelector("h1");
const letters = heading.querySelectorAll("span");

const timeline = new ViewTimeline({ subject: heading });
const scales = [/**/];
const rotations = [/**/];

for ([index, el] of letters.entries()) {
  el.animate(
    {
      scale: ["1", scales[index]],
      rotate: ["0deg", rotations[index]]
    },
    {
      timeline,
      fill: "both",
      rangeStart: "contain 30%",
      rangeEnd: "contain 70%",
      easing: "ease-out"
    }
  );
}

Выделение элементов, привязанных к прокрутке

Дети в учреждениях .

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

for (let item of items) {
  const timeline = new ViewTimeline({ subject: item, axis: "inline" });
  const animation = new Animation(effect, timeline);
  item.animate(
    {
      opacity: [0.3, 1, 0.3]
    },
    { timeline, easing: "ease-in-out", fill: "both" }
  );
  animation.rangeStart = "cover calc(50% - 100px)";
  animation.rangeEnd = "cover calc(50% + 100px)";
}

Анимация прокрутки, запускающая обычную анимацию

Бюджет .

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

const timeline = new ViewTimeline({
  subject: containerElement
});

// Setup scroll-driven animation
const scrollAnimation = containerElement.animate(
  {
    "--cover-color": ["blue", "lightblue"],
    scale: ["1 0.2", "1 3"]
  },
  {
    timeline,
    easing: "cubic-bezier(1, 0, 0, 0)",
    rangeStart: "cover 0%",
    rangeEnd: "cover 50%"
  }
);

// Wait for scroll-driven animation to complete
await scrollAnimation.finished;
scrollAnimation.cancel();

// Trigger time-driven animations
for (let [index, postElement] of postElements.entries()) {
  const animation = postElement?.animate(
    { scale: ["1 3", "1 1"] },
    {
      duration: 200,
      delay: index * 33,
      easing: "ease-out",
      fill: "backwards"
    }
  );
}

«Мы занимались анимацией, управляемой прокруткой, в течение длительного времени. До появления API веб-анимации нам приходилось использовать события прокрутки, которые позже объединялись с API Intersection Observer API. Часто это была очень трудоемкая задача, а теперь это стало тривиальным благодаря API веб-анимации и анимации, управляемой прокруткой», — Хельге Силсет, фронтенд-разработчик в NRK

NRK имеет множество различных веб-компонентов , которые можно подключить к одному из их пользовательских элементов, называемому ScrollAnimationDriver ( <scroll-animation-driver> ), поддерживающему следующие анимации:

  • Слои с [KeyframeEffects](https://developer.mozilla.org/docs/Web/API/KeyframeEffect)
  • Лотти анимации
  • mp4
  • три.js
  • <canvas>

В следующем примере используются слои с KeyframeEffects :

<scroll-animation-driver data-range-start='entry-crossing 50%' data-range-end='exit-crossing 50%'>
  <layered-animation-effect>
    <picture>
      <source />
      <img />
    </picture>

    <picture>
      <source />
      <img />
    </picture>

    <picture>
      <source />
      <img />
    </picture>
  </layered-animation-effect>
</scroll-animation-driver>

JavaScript-реализация NRK пользовательского элемента <scroll-animation-driver> :

export default class ScrollAnimationDriver extends HTMLElement {
  #timeline

  connectedCallback() {
    this.#timeline = new ViewTimeline({subject: this})
    for (const child of this.children) {
      for (const effect of child.effects ?? []) {
        this.#setupAnimationEffect(effect)
      }
    }
  }

  #setupAnimationEffect(effect) {
    const animation = new Animation(effect, this.#timeline) 
    animation.rangeStart = this.rangeStart
    animation.rangeEnd = this.rangeEnd

    if (this.prefersReducedMotion) {
      animation.currentTime = CSS.percent(this.defaultProgress * 100)
    } else {
      animation.play()
    }
  }
}

export default class LayeredAnimationEffect extends HTMLElement {
  get effects() {
    return this.layers.flatMap(layer => toKeyframeEffects(layer))
  }
}

Производительность прокрутки

У NRK была очень производительная реализация JavaScript до того, как стали использовать анимацию, управляемую прокруткой, но теперь анимация, управляемая прокруткой, позволяет им иметь еще лучшую производительность, не беспокоясь о зависаниях при прокрутке, даже на маломощных устройствах.

  • Длительность задачи без SDA: 1 мс.
  • Длительность задачи SDA: 0,16 мс.
Вкладка «Производительность» Chrome DevTools.
Запись на вкладке «Производительность» Chrome DevTools с замедлением ЦП в 6 раз показывает 0,16 мс для каждой задачи в новом кадре.

Чтобы узнать больше о разнице в производительности прокрутки между реализациями JavaScript и анимацией, управляемой прокруткой, более подробно рассматривается статья Пример использования анимации, управляемой прокруткой .

Вопросы доступности и UX

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

  • Уважение предпочтений пользователя в отношении уменьшения движения : использование screen and (prefers-reduced-motion: no-preference) для применения анимации в качестве постепенного улучшения. Также полезно одновременно обрабатывать стили печати.
  • Учитывая широкий спектр устройств и различную точность ввода при прокрутке : некоторые пользователи могут прокручивать пошагово (пробел или клавиши вверх/вниз, переход к ориентирам с помощью программы чтения с экрана) и не видеть всю анимацию. Убедитесь, что важная информация не пропущена.
  • Будьте осторожны с анимацией, показывающей или скрывающей контент . Пользователям, использующим масштабирование операционной системы (ОС), может быть трудно заметить, что скрытый контент появляется при прокрутке. Не заставляйте пользователей искать его. Если необходимо скрыть или показать контент, убедитесь, что он появляется и исчезает.
  • Избегайте больших изменений яркости или контрастности анимации . Поскольку анимация, управляемая прокруткой, зависит от контроля пользователя, резкие изменения яркости могут проявляться в виде мигания, что может вызвать судороги у некоторых пользователей.
@media (prefers-reduced-motion: no-preference) {
  .article-image {
    opacity: 0;
    transition: opacity 1s ease-in-out;
  }
  .article-image.visible {
    opacity: 1;
  }
}

Поддержка браузера

Для более широкой поддержки браузерами ScrollTimeline и ViewTimeline NRK использует полифил с открытым исходным кодом , в который вносит свой вклад активное сообщество .

В настоящее время полифил загружается условно, когда ScrollTimeline недоступен, и используется урезанная версия полифила без поддержки CSS.

if (!('ScrollTimeline' in window)) {
  await import('scroll-timeline.js')
}

Обнаружение и обработка поддержки браузера в CSS:

@supports not (animation-timeline: view()) {
  .article-section {
    translate: 0 calc(-15vh * var(--fallback-progress));
    opacity: var(--fallback-progress);
  }
}

@supports (animation-timeline: view()) {
  .article-section {
    animation: --fade-up linear;
    animation-timeline: view();
    animation-range: entry 100% exit 100%;
  }
}

В предыдущем примере для неподдерживаемых браузеров NRK использует переменную CSS --fallback-progress в качестве резерва для управления временной шкалой анимации для свойств translate и opacity .

Затем CSS-переменная --fallback-progress обновляется с помощью прослушивателя событий scroll и requestAnimationFrame в JavaScript следующим образом:

function updateProgress() {
  const end = el.offsetTop + el.offsetHeight;
  const start = end - window.innerHeight;
  const scrollTop = document.scrollingElement.scrollTop;
  const progress = (scrollTop - start) / (end - start);
  document.body.style.setProperty('--fallback-progress', clamp(progress, 0, 1));
}


if (!CSS.supports("animation-timeline: view()")) {
  document.addEventListener('scroll', () => {
    if (!visible || updating) {
      return;
    }

    window.requestAnimationFrame(() => {
      updateProgress();
      updating = false;
    });

    updating = true;
  });
}

Ресурсы

Особая благодарность Ханне Ван Опстал, Брамусу и Эндрю Кину Гуану из Google, а также Ингрид Рейме из NRK за их ценный вклад в эту работу.