Эффект parallax на чистом CSS
HTML&CSS

Эффект parallax на чистом CSS

Оригинал: Pure CSS Parallax Websites, Keith Clark

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

Параллакс чаще всего реализуется с помощью JavaScript и в большом количестве случаев плохо, модифицируя DOM непосредственно в обработчике scroll, что приводит к ненужным перерисовкам страницы. Все это не синхронизиовано с процессом рендеринга в браузере и приводит к выпадению кадров и заиканиям. С использованием requestAnimationFrame и отложенным обновлением DOM все не так плохо, но что, если вы можете обойтись вовсе без JavaScript?

Реализация параллакс-эффекта на CSS снимает все эти вопросы и позволяет браузеру использовать аппаратное ускорение. При этом результат согласуется с частотой кадров, и скроллинг получается гладким. Вы также можете комбинировать эффект с другими особенностями CSS, такими как media queries или supports  — и получить адаптивный параллакс.

Демо

Теория

Прежде, чем мы углубимся в то, как работает эффект, давайте создадим некую каркасную разметку.


<div class="parallax">
    <div class="parallax__layer parallax__layer--back">
        ...
    </div>
    <div class="parallax__layer parallax__layer--base">
        ...
    </div>
</div>

И добавим стили:


.parallax {
    perspective: 1px;
    height: 100vh;
    overflow-x: hidden;
    overflow-y: auto;
}
.parallax__layer {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}
.parallax__layer--base {
    transform: translateZ(0);
}
.parallax__layer--back {
    transform: translateZ(-1px);
}

Класс parallax — это то место, где будет происходить магия. Мы определили свойства height и perspective для этого класса, тем самым создали эффект глубины. Свойство overflow-y: auto позволяет скроллить контент внутри элемента обычным способом, но теперь вложенные элементы будут отрисовываться относительно фиксированной перспективы. В этом ключевой момент в создании эффекта параллакса.

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

Наконец, два класса parallax__layer--base и parallax__layer--back используются для определения скорости скроллинга, с помощью задания смещения по оси Z (перемещая дальше или ближе к плоскости просмотра).

Для простоты, я добавил только два слоя с разными скоростями — мы добавим больше далее.

Демо

Коррекция глубины

Поскольку параллакс создается с помощью 3D-преобразований, перемещение элемента вдоль оси Z имеет побочный эффект — при перемещении элемента ближе или дальше меняется его размер. Чтобы исправить это, мы должны применить трансформацию scale() к элементу, тогда он будет отрисовываться в оригинальном размере:


.parallax__layer--back {
    transform: translateZ(-1px) scale(2);
}

Коэффициент масштабирования можно рассчитать по формуле 1 + (translateZ * -1) / perspective. Например, если свойство perspective равно 1px, а элемент перемещен на -2px, коэффициент масштабирования равен 3:


.parallax__layer--deep {
    transform: translateZ(-2px) scale(3);
}
Демо

Управление скоростью слоя

Скорость слоя управляется комбинацией значения перспективы и смещения по оси Z. Элементы с отрицательными значениями смещения перемещаются медленее, чем с положительными. Чем дальше значение от 0, тем более выраженным получается эффект параллакса (т.е. элемент c translateZ(-10px) будет двигаться медленнее, чем с translateZ(-1px)).

Подразделы с параллаксом

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

Для начала нам необходим элемент parallax__group, в котором мы сгруппируем слои:


<div class="parallax">
    <div class="parallax__group">
        <div class="parallax__layer parallax__layer--back">
            ...
        </div>
        <div class="parallax__layer parallax__layer--base">
            ...
        </div>
    </div>
    <div class="parallax__group">
        ...
    </div>
</div>

CSS стили для этого элемента:


.parallax__group {
    position: relative;
    height: 100vh;
    transform-style: preserve-3d;
}

В этом примере я хочу, чтобы каждая группа заполняла вьюпорт, поэтому я задал высоту равную 100vh, однако для каждой группы могут при необходимости быть заданы свои значения. Свойство transform-style: preserve-3d предотвращает выравниваение дочерних элементов в одной плоскости, а свойство position: relative позволяет абсолютно спозиционировать относительно него дочерние элементы.

При группировке элементов необходимо помнить одно важное правило, мы не можем обрезать содержимое группы. Установка overflow: hidden для элемента parallax__group сломает эффект параллакса. Это приводит к тому, что дочерние элементы могут выходить за границы контейнера, поэтому здесь нужно правильно расставить значения z-index у групп, чтобы содержимое правильно показывалось/скрывалось при прокрутке страницы.

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


.parallax__group {
    transform: translate3d(700px, 0, -800px) rotateY(30deg);
}

Посмотрите на следующий пример, и не забудьте отметить опцию отладки!

Демо

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

  • Firefox, Safari, Opera и Chrome поддерживают этот эффект.
  • В Firefox есть небольшая проблема с выравниванием.
  • IE пока не поддерживает свойство preserve-3d, поэтому эффект параллакса работать не будет. Это нормально, но вы все равно должны убедиться, что содержимое корректно отображается без параллакса — ну вы знаете, прогрессивное улучшение и все такое!
Рассылка
Подпишитесь на рассылку и получайте дайджест новостей и статей.
Никакого спама!
Подписаться