Параллакс — это изменение видимого положения объекта относительно удалённого фона в зависимости от положения наблюдателя. Параллакс пришёл в веб из старых видеоигр. В них фоновые изображения перемещаются медленнее, чем изображения на переднем плане, чтобы создать иллюзию глубины двухмерной сцены, псевдо‑3Д:
Чтобы сделать такой сложный, многослойный параллакс понадобятся отдельные слои и ЦСС‑анимации, привязанные к прокрутке. Возьмём первые попавшиеся слои из бесплатного набора изображений для параллакса в играх:
Наложим их друг на друга:
<section class="parallax">
<img src="sky.png" class="parallax__sky">
<img src="mountains.png" class="parallax__mountains">
<img src="dunes.png" class="parallax__dunes">
<img src="city.png" class="parallax__city">
<img src="front.png" class="parallax__front">
</section>
.parallax {
display: grid;
grid-template-areas: 'stack';
}
.parallax > * {
grid-area: stack; /* Накладываем слои один на один */
}
.parallax > img {
width: 100%; /* Тянем картинки на весь контейнер */
height: 100%;
object-fit: cover;
}





Зазумим ближние слои:
:root {
--parallaxHeight: 80lvh;
--parallaxWidth: 100vw;
--parallaxTopColor: #fdf8f1;
--parallaxBottomColor: #bf6f4a;
}
.parallax {
display: grid;
grid-template-areas: 'stack';
height: var(--parallaxHeight);
overflow: clip; /* Чтобы слои параллакса при движении не вылезали за границу контейнера */
}
.parallax > * {
grid-area: stack;
}
.parallax > img {
width: 100%;
height: 100%;
object-fit: cover;
min-width: calc(100% * var(--zoom, 1));
min-height: calc(100% * var(--zoom, 1));
margin-top: calc(var(--parallaxHeight) * ((1 - var(--zoom, 1)) / 2)); /* Скомпенсируем положение слоёв, чтобы после зума центр слоя оставался на том же месте */
margin-left: calc(var(--parallaxWidth) * ((1 - var(--zoom, 1)) / 2));
image-rendering: pixelated; /* Чтобы слои не мылились при увеличении изображения, сохраняя «пиксельность» */
will-change: transform;
}
.parallax__sky {
--zoom: 1;
}
.parallax__mountains {
--zoom: 1;
}
.parallax__dunes {
--zoom: 1.2;
}
.parallax__city {
--zoom: 1.25;
}
.parallax__front {
--zoom: 1.32;
}





Добавим анимацию. При прокрутке будем двигать слои по вертикали с разной скоростью:
:root {
--parallaxHeight: 80lvh;
--parallaxWidth: 100vw;
--parallaxTopColor: #fdf8f1;
--parallaxBottomColor: #bf6f4a;
--parallaxScrollHeight: 200px;
}
body {
background: var(--parallaxBottomColor);
min-height: calc(100lvh + var(--parallaxScrollHeight)); /* Чтобы нам было куда крутить */
}
.parallax {
display: grid;
grid-template-areas: 'stack';
height: var(--parallaxHeight);
overflow: clip;
background-color: var(--parallaxTopColor);
}
.parallax > * {
grid-area: stack;
animation: parallax linear both; /* Указываем анимацию */
animation-timeline: scroll(); /* Просим браузер анимировать при прокрутке окна */
animation-range: 0 var(--parallaxScrollHeight); /* При прокрутке от 0 до 200 пк */
}
@keyframes parallax { /* Анимация слоёв: двигаем по вертикали с заданной скоростью */
to {
transform: translateY(calc(var(--parallaxSpeed, 1) * 2px));
}
}
.parallax > img {
width: 100%;
height: 100%;
object-fit: cover;
min-width: calc(100% * var(--zoom, 1));
min-height: calc(100% * var(--zoom, 1));
margin-top: calc(var(--parallaxHeight) * ((1 - var(--zoom, 1)) / 2));
margin-left: calc(var(--parallaxWidth) * ((1 - var(--zoom, 1)) / 2));
image-rendering: pixelated;
will-change: transform;
}
/* Задаём разную скорость и приближение для слоёв */
.parallax__sky {
--parallaxSpeed: 50;
--zoom: 1;
}
.parallax__mountains {
--parallaxSpeed: 40;
--zoom: 1;
}
.parallax__dunes {
--parallaxSpeed: 30;
--zoom: 1.2;
}
.parallax__city {
--parallaxSpeed: 20;
--zoom: 1.25;
}
.parallax__front {
--parallaxSpeed: 10;
--zoom: 1.32;
}
Сафари и Файрфокс пока не поддерживают анимации, привязанные к прокрутке. Для них подключим полифил — крошечную библиотеку на Яваскрипте, эмулирующую пока не поддерживаемую браузером фичу. В нашем случае полифил добавляет поддержку animation-timeline: scroll()
<!doctype html>
<html lang="ru"
<head>
<!-- ... -->
<script src="https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js"></script>
</head>
<body>
<!-- ... -->
</body>
</html>
P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.