Если вы хотите, чтобы сайт вызывал «вау-эффект», а ссылками на него делились, используйте параллакс. С ним сайты выглядят объёмно, а элементы могут плавно перемещаться при прокрутке страницы или движении курсора.

В этой статье мы покажем, как сделать параллакс на чистом CSS и JavaScript, поговорим про некоторые JS-библиотеки и посмотрим, как оптимизировать анимацию.

Пример параллакса на CSS. Outer Studio, источник
Пример параллакса на CSS. Outer Studio, источник

На чём делать параллакс-эффект: CSS или JavaScript

Параллакс при прокрутке страниц создают с помощью 3D трансформаций: transform-style: preserve-3dperspectivetransform: translateZ и других.

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

А вот параллакс по движению мыши создаётся на JavaScript. В CSS пока нет подходящих для этого свойств, но с его помощью можно оптимизировать параллакс-эффект.

Как сделать параллакс на чистом CSS

Как задать элементу глубину

Чтобы задать элементу глубину, нужно применить к нему transform: translateZ; и указать значение свойства perspective.

Разработчики позиционируют элементы на странице по двум осям: Х и Y, по вертикали и горизонтали. Но есть и третья ось — Z, которая отражает глубину элемента и его расстояние до пользователя. Если просто сдвинуть элемент по этой оси, задав ему свойство transform: translateZ, то мы не увидим разницы. Элемент пока находится в двухмерной плоскости, ведь экран смартфона или монитор ноутбука не обладают глубиной.

Сделать плоскость трёхмерной можно с помощью CSS-свойства perspective. В качестве значения оно принимает расстояние от элемента до пользователя по оси Z — чем больше это значение, тем дальше элемент от вас находится, и наоборот. Часто для perspective указывают значение в 1px — этого достаточно, чтобы установить глубину перспективы.

Пример параллакс-эффекта на чистом CSS

Сделаем параллакс при прокрутке страницы. Сначала подготовим разметку блока с параллаксом. Добавляем <div> — родитель с классом parallax. Внутри него создаём два элемента-слоя с классами parallax-layer. Первый элемент — <div> с изображением, второй — <span> с текстом. Указываем для <div> дополнительный класс parallax-image, а для <span> — parallax-text.

<div class="wrapper parallax">
  <div class="parallax-layer parallax-image">
    <img src="<https://i.pinimg.com/originals/9e/20/fc/9e20fc9ba2e1456ff29caa6780521cb7.jpg>" alt="Сад изящных слов">
  </div>
  <span class="parallax-layer parallax-text">Сад изящных слов</span>
</div>

Задаём <div>-родителю свойство perspective: 1px. Оно создаёт виртуальную 3D-плоскость, указывая, что центр блока parallax — исходная точка построения перспективы. Добавляем overflow-y: auto, чтобы прокручивать элементы-потомки относительно фиксированной точки.

.parallax {
  perspective: 1px;
  height: 100vh;
  overflow-y: auto;
}

Теперь удаляем внутренние элементы с классом parallax-layer из общего потока и растягиваем на всю площадь родителя.

.parallax-layer {
  position: absolute;
  inset: 0; // вместо top, bottom, left, right: 0;
}

Остаётся задать смещение по оси Z. Текст будет дальше от пользователя, а фон ближе — за счёт этого мы создадим параллакс-эффект.

.parallax-image {
  transform: translateZ(0);
}

.parallax-text {
  transform: translateZ(-2px);
}

Добавим стили и получим результат:

See the Pen parallax by Mikhail (@smfms) on CodePen.

Если открыть вкладку с CSS, можно заметить, что для блока parallax-text задан scale(3) — то есть элемент увеличен в три раза. Зачем мы это сделали?

Дело в том, что элемент, отдаляясь от нас в 3D-плоскости, визуально уменьшается в размерах. И наоборот, приближаясь — увеличивается. Чтобы компенсировать эти изменения, мы используем scale. А его значение вычисляем по формуле:

1 + (translateZ * −1) / perspective

В нашем случае вычисление будет таким:

1 + (-2 * −1) / −1

Мы добились параллакс-эффекта на чистом CSS. Все использованные свойства поддерживаются современными браузерами. При желании можно добавить другие элементы в блок parallax и играть с их смещением по оси Z. Главное — не забывайте, что при изменении положения по этой оси меняются и размеры элемента, поэтому значение scale надо корректировать.

Пример параллакса с множеством элементов. Автор — Скотт Келлум, CodePen

See the Pen Sass parallax example by Scott Kellum (@scottkellum) on CodePen.

⭐ Научитесь делать анимации разного уровня сложности — записывайтесь на наш курс. Вы узнаете, как анимировать слайдер, бургер-меню и аккордеон, как создавать карточки товаров с 3D-эффектом, многослойный параллакс и параллакс шапки.

Как сделать параллакс на JavaScript

Теперь создадим параллакс-эффект на JavaScript: сделаем карточку с несколькими элементами, которые будут смещаться при движении курсора — каждый со своей скоростью. Так как элементы смещаются по осям X и Y, это будет 2D-параллакс.

Для начала напишем разметку, похожую на ту, что мы использовали в прошлом примере. Нам нужны <div>-обёртка и внутренние анимируемые элементы:

<div class="parallax">
  <div class="parallax__inner">
    <h1 class="parallax__layer title">
      Здорово быть енотом!
    </h1>

    <button class="parallax__layer button" type="button">
	 Стать енотом
    </button>

    <div class="parallax__layer circle"></div>
  </div>
</div>

Стили:

.parallax__inner {
  position: relative;
  overflow: hidden;
}

.parallax__layer {
  transition: transform 0.3s linear;
}

Уже сейчас можно задать характер анимации при смещении элементов, указав свойство transition для элементов параллакса. Для более точной настройки можно использовать кривые Безье. Но не рекомендуем использовать значение ease-in-out: могут появиться «рывки» при быстром движении курсора, ведь функция не обладает достаточной линейностью.

Пример «рывков» при быстром перемещении курсора
Пример «рывков» при быстром перемещении курсора

Перейдём к JavaScript. Найдём параллакс-родитель и все параллакс-элементы, а затем добавим обработчик на родитель. Будем слушать движение курсора мыши — mousemove.

const wrapper = document.querySelector('.parallax__inner');
const layers = document.querySelectorAll('.parallax__layer');

wrapper.addEventListener('mousemove', initParallax);

Опишем функцию initParallax, в которой будем вести расчёты. Далее декомпозируем задачу: сначала найдём координаты курсора относительно карточки, а затем вычислим новые координаты для элементов при срабатывании события мыши.

Всегда вычисляйте координаты относительно того блока, на котором слушается событие мыши — тогда расчёты будут точными. Если вычислять координаты курсора относительно вьюпорта, то смещение параллакс-элементов будет рассчитываться неправильно, так как пропорции вьюпорта и карточки, скорее всего, не будут совпадать.

Сначала вычислим координаты. В JS нет метода, который возвращал бы координаты курсора относительно нужного блока. Свойство clientX возвращает положение по оси X относительно начала вьюпорта. Чтобы начало блока parallax совпадало с 0 по оси X, надо из положения относительно экрана вычесть левый отступ блока parallax. В этом нам поможет метод getBoundingClientRect().

Перейдём к вычислениям. Для удобства записываем текущую координату в переменную и следом добавляем переменную parallaxLeftOffset с внешним отступом блока wrapper от границ экрана. Будем вычитать отступ из текущей позиции курсора и записывать это в переменную coordX:

const initParallax = (evt) => {
  const clientX = evt.clientX;
  const clientY = evt.clientY;

  const parallaxLeftOffset = wrapper.getBoundingClientRect().left;
  const coordX = clientX - parallaxLeftOffset;
  const coordY = clientY - parallaxTopOffset;
}

Теперь левая граница параллакс-блока совпадает с координатой 0. Это не совсем правильно, ведь мы можем отслеживать изменения курсора только вправо. Нужно сделать так, чтобы центр блока совпадал с координатой 0. Для этого дополнительно вычтем половину ширины блока.

const coordX = clientX - parallaxLeftOffset - (0.5 * wrapper.offsetWidth);
const coordX = clientY - parallaxTopOffset - (0.5 * wrapper.offsetHeight);

Чтобы получить ширину, используем свойство offsetWidth. Теперь центр враппера — точка с координатами 0.0. Можно двигаться к самому интересному.

Мы вычислили положение курсора относительно параллакс-блока. Теперь мы можем рассчитать смещение его элементов и задать им его:

layers.forEach((layer)=>{
  const x = (coordX).toFixed(2);
  const y = (coordY).toFixed(2);
  layer.setAttribute('style', `transform: translate(${x}px, ${y}px);`)
});

Округляем координату с помощью метода toFixed и задаём каждому элементу трансформацию по обеим осям. Вот что получилось:

See the Pen Untitled by Mikhail (@smfms) on CodePen.

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

Будем умножать вычисленную координату на этот коэффициент.

Код работает, но мы забыли о сути параллакса. Параллакс — это смещение элементов с разной скоростью, а сейчас все элементы двигаются с одинаковой.

Изменим это. Коэффициент скорости будем хранить прямо в разметке в data-атрибуте, так как это удобно.

<div class="parallax">
  <div class="parallax__inner">
    <h1 class="parallax__layer title" data-speed="0.03">
      Здорово быть енотом!
    </h1>

    <button class="parallax__layer button" type="button" data-speed="0.05">
      Стать енотом
    </button>

    <div class="parallax__layer circle" data-speed="0.18"></div>
  </div>
</div>

Значение не должно быть слишком большим, чтобы элементы двигались плавно. Допишем скрипт с поправкой на скорость:

layers.forEach((layer)=>{
    const layerSpeed = layer.dataset.speed;
    const x = (coordX * layerSpeed).toFixed(2);
    const y = (coordY * layerSpeed).toFixed(2);
    layer.setAttribute('style', `transform: translate(${x}px, ${y}px);`)
});

Теперь элементы двигаются с разной скоростью. Последний штрих: инвертируем значение смещаемых координат, чтобы при движении мыши влево элементы смещались вправо, и наоборот. Готово!

See the Pen Untitled by Mikhail (@smfms) on CodePen.

Как оптимизировать параллакс

В начале статьи мы упомянули, что параллакс ресурсозатратен для браузера — на каждое движение мыши вызывается несколько команд по перерасчёту координат. Что можно с этим сделать?

Не смещайте элементы с помощью свойств top, left, right, bottom. Вместо них лучше использовать transform: translateX, translateY — они снижают нагрузку на графический процессор.

В CSS есть свойство will-change. Если задать ему значение transform, то браузер ещё до анимирования выполнит оптимизации. Это снизит нагрузку на графический процессор, и анимация будет работать плавнее, без рывков.

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

Заключение

Мы показали простые способы создания параллакса на CSS и JS, но иногда нужны более сложные эффекты. Для таких случаев есть специальные библиотеки, например, Loco Scrollparallax JS или rellax. С их помощью можно управлять направлением движения элементов, фиксировать слайды при прокрутке, создавать эффект «спешки» или «задержки» анимации.

Узнать больше


«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

ТелеграмПодкастБесплатные учебники

Читать дальше

Игры с бесконечностью, или зачем нам infinity в CSS

Игры с бесконечностью, или зачем нам infinity в CSS

💡 Это перевод статьи Will Boyd из блога CodersBlock. Оригинал: https://codersblock.com/blog/playing-with-infinity-in-css/

В CSS есть константа Infinity. Когда я только узнал об этом, ко мне в голову сразу пришла гора абсурдных идей, как это использовать, среди которых была и пара неплохих.

Ну, мне так кажется.

Кстати, если что, infinity можно использовать только внутри calc(). Ну, поехали!

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Читать дальше
CSS
  • 5 марта 2024
Межстрочное расстояние в CSS. Свойство line-height

Межстрочное расстояние в CSS. Свойство line-height

line-height задает интерлиньяж, то есть расстояние между базовыми линиями соседних строк текста. Это свойство может влиять на читабельность текста и его восприятие.

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Значение line-height можно указывать как в абсолютных единицах (например, px, pt), так и в относительных (em, %, без единицы измерения). Рекомендуется использовать относительные единицы, так как они позволяют сохранить масштабируемость и адаптивность текста.

Примеры использования:

  • line-height: 1.2; — относительное значение, не зависящее от размера шрифта.
  • line-height: 20px; — абсолютное значение, фиксированный размер интерлиньяжа.
  • line-height: 1.5em; — относительное значение, зависящее от размера шрифта элемента.
Читать дальше
CSS
  • 4 марта 2024
Свойство text-align

Свойство text-align

Свойство text-align в CSS используется для определения горизонтального выравнивания текста внутри элемента.

🚀 Сегодня вам бесплатно доступны тренажёры по HTML и CSS.

Свойство text-align может принимать несколько значений, включая:

  • left — выравнивает текст по левому краю контейнера.
  • right — выравнивает текст по правому краю контейнера.
  • center — центрирует текст внутри контейнера.
  • justify — выравнивание текста по ширине. Оба края текста (левый и правый) будут выровнены по краям контейнера.

Пример использования свойства text-align:

p {
  text-align: center;
}

Этот код выравнивает текст внутри всех параграфов (<p>) по центру.

Для практики и улучшения своих навыков работы с text-align и другими свойствами CSS, рекомендуем пройти тренажёр. Он поможет лучше понять, как работает выравнивание текста, и даст возможность попрактиковаться в использовании различных значений свойства text-align.

CSS
  • 4 марта 2024
CSS-препроцессоры в 2024. Большой обзор

CSS-препроцессоры в 2024. Большой обзор

Препроцессоры позволяют разработчикам расширить возможности CSS. Например, они добавляют селекторы наследования, вложенные правила, примеси и многие другие.

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

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Читать дальше
CSS
  • 29 февраля 2024
Как прятать

Как прятать

Когда display: none, а когда visibility: hidden? — спрашивает нас RedFox. Зависит от того, что вы пытаетесь сделать. Есть и другие варианты как спрятать блок и даже специальный атрибут. Давайте разберёмся!

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Если вам приходится что-то прятать, то лучше всего это вообще убрать: сайт легче, код чище... ошибок меньше! Но если вам нужно, чтобы оно там пряталось до поры, а потом кому-то пригодилось — это другое дело. Здесь важно не ошибиться с выбором способа.

Читать дальше
CSS
  • 28 февраля 2024
Новое в 2023 — text-wrap: balance

Новое в 2023 — text-wrap: balance

В 2023 в CSS появилось любопытное свойство text-wrap со значением balance. Оно «уравновешивает» текстовые элементы, чтобы они приятнее выравнивались внутри блока.

h1 {
  text-wrap: balance;
}

Ограничение — текст не длиннее 6 строк, иначе браузеру придётся непросто, и лучше не применять это свойство к body.

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Вот пример заголовка <h1>text-wrap: balance и без него.

На момент написания заметки свойство поддерживается во всех больших браузерах, кроме Safari, а на мобильных — только в Chrome, но то ли ещё будет.

CSS
  • 13 ноября 2023
Знакомство с CSS

Знакомство с CSS

После того как мы разобрались с базовой структурой веб-страницы с помощью HTML, пришло время привнести в неё стиль и красоту. В этом нам поможет CSS, что означает Cascading Style Sheets, или «каскадные таблицы стилей».

CSS используется для оформления HTML-страниц. Если HTML — это скелет сайта, то CSS — его одежда. С помощью CSS мы можем задавать цвета, шрифты, отступы, добавлять анимации и многое другое.

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Читать дальше
CSS
  • 1 ноября 2023
Увеличение ссылки при наведении

Увеличение ссылки при наведении

Задача: плавно увеличить ссылку при наведении.

Решение:

a {
  display: inline-block;
  transition: transform 0.3s ease;
}
a:hover {
  transform: scale(1.2);
}

Первые два свойства просто немного меняют вид ссылки. Свойство color: maroon; меняет цвет текста в тегах <a> на темно-красный, а свойство text-decoration: none; убирает подчеркивание.

Но наша задача — плавно увеличить размер ссылки, а не просто её перекрасить. Поэтому используем свойство transform: scale(1.2), которое срабатывает при наведении курсора и увеличивает размер ссылки в 1.2 раза по сравнению с её начальным размером.

Демо:

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Читать дальше
CSS
  • 13 октября 2023
WOFF больше не нужен

WOFF больше не нужен

Я купил и скачал шрифты для недавнего проекта, распаковал папку, где были только WOFF2-файлы, и сначала не поверил, что такое бывает.

Потом мне стало интересно: они что, забыли WOFF? А он вообще ещё нужен? Ну, всё-таки, веб — это место, где постоянно всё меняется и улучшается, поэтому я пошёл и спросил людей в Mastodon. Ответ был единодушным: нужен только WOFF2!

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Я хорошо помню пост от Зака в конце 2016, после которого я отказался от исчерпывающего синтаксиса @font-face, включавшего TTF, EOT и SVG-шрифты, и перешёл только на WOFF2 и WOFF.

Похоже, с тех пор мир веб-шрифтов изменился ещё разок, и вот актуальная версия @font-face:

@font-face {

  font-family: "Open Sans";
  src: url("opensans.woff2") format('woff2');

}

Остался всего один формат. Просто, скажите?

Как писал Зак, «так как в вебе, когда шрифт не найден, всё равно подгружаются системные шрифты, мы можем идти в ногу со временем». Итак, какие браузеры отправятся в тёмные века системных шрифтов с этим синтаксисом?

  • IE 11, 10, 9, 8, 7, …
  • Chrome 4–35
  • Edge 12 и 13
  • Safari 3–9.1
  • Firefox 2–38
  • Opera 22 и ниже
  • Android 4.4.4 KitKat и ниже (а это <0.5% устройств на Android)
  • Safari на iOS 3.2–9.3

Caniuse.com показывает, что почти у 95% пользователей есть браузер с поддержкой WOFF2. А в относительной статистике (Date Relative — прим. перев.) заметно, что массовый переход на WOFF2 случился в 2015 и 2016. К концу 2016 во всех последних версиях больших браузеров появилась поддержка WOFF2.3

А спустя 7 лет поддержка расширилась настолько, что можно уже не добавлять в проект WOFF-файлы — ну, кроме случая, когда вы точно знаете, что много ваших пользователей используют старые устройства и браузеры.

С другой стороны, нет смысла и удалять WOFF из старых проектов. Если вы подключали WOFF2 раньше WOFF внутри @font-face — и порядок здесь важен — то браузер просто скачает и подключит WOFF2-версию.

И если однажды вы, как и я, обнаружите себя перед папкой, полной файлов WOFF2, знайте, что WOFF — уже всё.

CSS
  • 23 сентября 2023
Трясём пароль с помощью CSS

Трясём пароль с помощью CSS

Знаете момент, когда всё на сайте уже сделано, и хочется добавить какую-нибудь маленькую незаметную фишку? Мы тоже знаем, поэтому давайте просто потрясём поле пароля, когда пользователь ввёл неверный пароль. Как на Маке.

🚀 Сегодня вам бесплатно доступен тренажёр по HTML и CSS.

Вот что получится в итоге:

Читать дальше
CSS
  • 7 сентября 2023