Александр!

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

Под капотом — стандартный браузерный АПИ веб‑анимаций и немного кода для привязки его к скроллу

Покажу на примере, как сделать похожее. Возьмём несколько дивов с фоном и заполним ими 1,5 экрана:

<style>
.prospect {
  /*
    Фиксируем высоту контейнера, чтобы с помощью flex-grow
    распределить в нём место
  */

  --prospectHeight: 150vh;
  /*
     Фиксируем ширину рядов. Она должна быть больше
     ширины экрана, чтобы было, что прокручивать
  */
  --prospectWidth: 150vw;

  /* Задаем максимальный межстрочник и межколонник */
  --prospectGutter: 30px;

  height: var(--prospectHeight);
  display: flex;
  flex-flow: column;
  overflow: hidden;
}

.prospect > div {
  width: var(--prospectWidth);
  /*
     Масштабируем ряды в соответствии с коэффициентом,
     заданным им вручную через ЦСС-переменные
  */
  flex-grow: var(--factor);
}

.prospect div:not(:last-child) {
  /* Аналогично масштабируем межстрочник */
  margin-bottom: calc(var(--prospectGutter) * var(--factor));
}
</style>
 
<div class="prospect">
  <div style="--factor: .5; --speed: 1"></div>
  <div style="--factor: .45; --speed: 1.25"></div>
  <div style="--factor: .35; --speed: 1"></div>
  <div style="--factor: .3; --speed: 1.15"></div>
  <div style="--factor: .25; --speed: 1"></div>
  <div style="--factor: .175; --speed: .9"></div>
  <div style="--factor: .1; --speed: 1"></div>
  <div style="--factor: .05; --speed: .8"></div>
  <div style="--factor: .045; --speed: .75"></div>
  <div style="--factor: .035; --speed: .7"></div>
  <div style="--factor: .025; --speed: .65"></div>
  <div style="--factor: .02; --speed: .6"></div>
</div>

Пусть нечётные ряды двигаются справа налево, а чётные — слева направо. Анимируем их:

// Описываем анимации для чётных и нечётных рядов
const oddAnimation = [
  { transform: 'translateX(0)', offset: 0 },
  { transform: 'translateX(-50vw)', offset: 1 },
]

const evenAnimation = [
  { transform: 'translateX(-50vw)', offset: 0 },
  { transform: 'translateX(0)', offset: 1 },
]

const prospect = document.querySelector('.prospect')
const prospectRows = document.querySelectorAll('.prospect > div')

// Определяем координаты контейнера и задаём границы анимации:
// анимация начнётся с верхней границы блока и закончится на нижней
const initialScrollTop = window.pageYOffset
const prospectRect = prospect.getBoundingClientRect()
const animateFrom = initialScrollTop + prospectRect.top
const animateTo = initialScrollTop + prospectRect.bottom

// Собираем массив анимированных рядов
const animations = Array.from(prospectRows).map((row, index) => {
  const animation = (index + 1) % 2 === 0 ? evenAnimation : oddAnimation
  const speedFactor = row.style.getPropertyValue('--speed')
  
  // Инициализируем анимацию ряда и тут же ставим её на паузу:
  // мы сами будем перематывать анимацию в зависимости от позиции скролла
  const player = row.animate(animation, { duration: 1 })
  player.pause()

  return { player, speedFactor }
})


const animate = () => {
  const scrollTop = window.pageYOffset
  // Определяем, какой процент анимации уже проскроллили
  const scrollPosition = (scrollTop - animateFrom) / (animateTo - animateFrom)
  
  animations.forEach((animation) => {
    let animationPosition = scrollPosition * animation.speedFactor
    // Обрабатываем пограничные случаи: не даём анимации закончиться
    if (animationPosition < 0) animationPosition = 0
    if (animationPosition >= 1) animationPosition = 0.999
    
    // Перематываем анимацию на нужный нам кадр
    animation.player.currentTime = animationPosition
  })
  
  // В боевых проектах стоит затротлить этот вызов
  requestAnimationFrame(animate)
}

animate()

P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.

Веб‑разработка
Отправить
Поделиться
Запинить

Рекомендуем другие советы