Александр!
Какой‑то готовой библиотеки здесь нет. Дизайнеры сами собрали эту анимацию, используя средства, встроенные в движок сайта:
Покажу на примере, как сделать похожее. Возьмём несколько дивов с фоном и заполним ими 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. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.