Как создать параллакс скроллинг на своем сайте?

JavaScript
25104 просмотра

Параллакс скроллинг — это когда элементы заднего плана движутся медленнее переднего при прокрутке страницы. Эффект параллакса создаёт ощущение глубины и делает лендинги запоминающимися. В этой статье разберём, как сделать CSS параллакс для сайта с нуля: возьмём за основу знаменитый сайт игры Firewatch и повторим его эффект — на чистом JavaScript.

Финальный результат — девять слоёв изображения, каждый из которых при прокрутке смещается с разной скоростью. Слои ближе к «зрителю» двигаются быстрее, дальние — медленнее. Именно это и создаёт иллюзию трёхмерного пространства.

Быстрая навигация:

Как работает эффект параллакса

Суть метода — слои параллакса фиксируются на экране через CSS-свойство position: fixed (элемент остаётся на одном месте при прокрутке, как будто приклеен к экрану), а затем JavaScript смещает каждый слой по вертикали пропорционально позиции прокрутки. Чем больше коэффициент скорости у слоя, тем быстрее он уходит вверх. Когда пользователь докручивает страницу до основного контента, тот перекрывает параллакс-слои за счёт z-index — CSS-свойства, которое управляет порядком наложения элементов по оси глубины.

Формула смещения слоя проста:

// yPos — смещение слоя в пикселях (отрицательное, чтобы слой уходил вверх)
// scrollY — текущая позиция прокрутки страницы в пикселях
// speed — коэффициент слоя от 0 (не движется) до 100 (движется синхронно с прокруткой)
yPos = -(scrollY * speed / 100)

Где scrollY — текущая позиция прокрутки в пикселях, а speed — коэффициент от 0 до 100, который задаётся каждому слою через атрибут data-speed . Задний слой с data-speed="2" почти не движется, передний с data-speed="100" уходит синхронно с прокруткой.

Подготовка графики

Изображение для параллакса нарезается на слои — PNG-файлы с прозрачностью. Каждый слой содержит только «свою» часть картины: небо, горы вдали, лес ближе, передний план. Для нашего примера — девять слоёв из оригинальной графики Firewatch.

Девять слоёв изображения для параллакс эффекта на CSS и JS

Для нарезки своей графики используйте Photoshop или Figma. Экспортируйте каждый слой как PNG с прозрачным фоном. Слои должны быть одинакового размера — это важно для корректного позиционирования. Скачайте слои из примера, чтобы сразу запустить демо:

Скачать слои (PNG) parallax-layers.zip 0.6 MB

Шаг 1 — HTML-разметка

Создаём контейнер .parallax с девятью слоями внутри. Каждый слой получает id для фонового изображения и атрибут data-speed для управления скоростью прокрутки. Ключевая деталь — инлайновый style="transform: translate3d(0px, 0px, 0px)" на каждом слое: он инициализирует трансформ прямо в HTML, до того как выполнится любой JavaScript. Браузер рисует слои правильно с первого кадра — без артефактов при загрузке или переключении вкладок. Слой 8 — особый: он position: absolute и JavaScript его не анимирует, поэтому инлайновый трансформ ему не нужен.

<div class="parallax">
    <div class="parallax__layer" id="parallax-0" data-speed="2"   style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-1" data-speed="5"   style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-2" data-speed="11"  style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-3" data-speed="16"  style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-4" data-speed="26"  style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-5" data-speed="36"  style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-6" data-speed="49"  style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-7" data-speed="69"  style="transform: translate3d(0px, 0px, 0px)"></div>
    <div class="parallax__layer" id="parallax-8" data-speed="100"></div>
</div>

<div class="maincontent">
    <!-- Основной контент страницы -->
</div>

Шаг 2 — CSS для параллакса

Зададим высоту параллакс-зоны и зафиксируем слои. Ключевые свойства:

  • position: fixed — слои остаются на месте, пока JavaScript их не сдвигает
  • background-size: auto 1038px — изображения масштабируются по высоте, растягиваясь по горизонтали через repeat-x
  • z-index: 10 / 99 — контент поверх параллакса при прокрутке
  • position: relative на контейнере .parallax — создаёт контекст позиционирования для последнего слоя
  • #parallax-8 { position: absolute } — последний слой выключается из анимации и прокручивается браузером нативно: без JS-задержки, без щели при скролле вверх
html, body {
    margin: 0;
    background-color: #210002;
}

.parallax,
.parallax__layer {
    height: 1000px;
}

.parallax {
    position: relative;
}

.parallax__layer {
    position: fixed;
    width: 100%;
    background-position: bottom center;
    background-size: auto 1038px;
    background-repeat: repeat-x;
    z-index: 10;
}

#parallax-8 {
    position: absolute;
}

.maincontent {
    position: relative;
    width: 100%;
    min-height: 300vh;
    z-index: 99;
    background-color: #210002;
}

Теперь назначим каждому слою своё фоновое изображение:

#parallax-0 { background-image: url(img/layer0.png); background-color: #ffaf1b; }
#parallax-1 { background-image: url(img/layer1.png); }
#parallax-2 { background-image: url(img/layer2.png); }
#parallax-3 { background-image: url(img/layer3.png); }
#parallax-4 { background-image: url(img/layer4.png); }
#parallax-5 { background-image: url(img/layer5.png); }
#parallax-6 { background-image: url(img/layer6.png); }
#parallax-7 { background-image: url(img/layer7.png); }
#parallax-8 { background-image: url(img/layer8.png); }

Шаг 3 — JavaScript

Вешаем обработчик scroll на window. При каждом событии читаем pageYOffset и перебираем все слои в цикле: вычисляем смещение и записываем его через setAttribute — именно так устроен оригинальный сайт Firewatch. Слой 8 пропускаем — он position: absolute и прокручивается браузером нативно без задержек. Никакого jQuery, никаких фреймворков.

window.addEventListener('scroll', function() {
    var top = window.pageYOffset;
    var layers = document.getElementsByClassName('parallax__layer');
    for (var i = 0; i < layers.length; i++) {
        if (layers[i].id === 'parallax-8') continue;
        var speed = layers[i].getAttribute('data-speed');
        layers[i].setAttribute('style', 'transform: translate3d(0px, ' + -(top * speed / 100) + 'px, 0px)');
    }
});

Нюансы и оптимизация

Отключайте параллакс на мобильных

На мобильных устройствах, особенно iOS, position: fixed ведёт себя непредсказуемо — слои могут прыгать или залипать при инерционном скролле. Проще всего отключить параллакс через медиазапрос в CSS:

@media (max-width: 767px) {
    .parallax__layer {
        position: absolute;
        transform: none !important;
    }
}

Уважайте настройки доступности

Часть пользователей отключает анимации через системные настройки («Уменьшить движение» в macOS/iOS). Параллакс для них лучше полностью убрать:

@media (prefers-reduced-motion: reduce) {
    .parallax__layer {
        position: absolute;
        transform: none !important;
    }
}

Добавьте прелоадер

Девять изображений — это девять HTTP-запросов. При медленном соединении слои будут «проявляться» один за другим прямо на глазах у пользователя. Решение — скрыть слои до полной загрузки страницы:

/* Скрываем слои до загрузки */
.parallax__layer {
    opacity: 0;
    transition: opacity 0.4s;
}

.parallax.is-loaded .parallax__layer {
    opacity: 1;
}
window.addEventListener('load', function() {
    document.querySelector('.parallax').classList.add('is-loaded');
});

Если хотите добавить параллакс проще и быстрее — посмотрите на библиотеку Simple Parallax: она делает всю работу за вас в три строки кода. В блоге есть отдельная статья с разбором.

Скачайте готовый архив с финальным кодом и всеми слоями изображения:

Скачать исходники parallax.zip 0.6 MB
Вам может быть интересно:
Swiper.js — слайдер для сайта: настройки и примеры
Swiper.js — как подключить и настроить слайдер на сайте
Что такое функция в программировании — типы и примеры на JavaScript и Python
Что такое функция в программировании?
Promise в JavaScript — промисы JS простыми словами для начинающих
Promise в JavaScript простыми словами — полное руководство
Анимация частиц и GLSL-шейдеры в PixiJS 8 — живой пример в браузере
Изучаем PixiJS. Часть 2 — продвинутая анимация и GLSL-шейдеры
Комментарии 0 Разные мнения приветствуются. Здесь можно спорить и обсуждать, но уважительно и без токсичности.
Отмена