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

В этой статье мы покажем, как сделать параллакс на чистом 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. С их помощью можно управлять направлением движения элементов, фиксировать слайды при прокрутке, создавать эффект «спешки» или «задержки» анимации.

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


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

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

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

Как размыть фон под элементом с помощью backrop-filter

Как размыть фон под элементом с помощью backrop-filter

В сентябре 2024 в Baseline в статусе Widely-available вошло CSS-свойство backdrop-filter. Оно делает красивое: позволяет применить фильтры (размытие, контраст, яркость, и прочее) к фону за элементом. Не к самому элементу, а именно к тому, что за ним — это важно.

То есть если у вас есть модальное с полупрозрачным фоном, вы можете сделать так, чтобы то, что под ней, красиво размывалось, как в macOS или на айфоне. Это и есть главное применение backdrop-filter.

Пример минимального кода:

<div class="glass-panel">Контент</div>

.glass-panel {
  backdrop-filter: blur(10px);
  background-color: rgba(255, 255, 255, 0.3);
}

Чтобы это работало, у элемента должен быть фон с прозрачностью (например, rgba или hsla), иначе фильтр не виден. И да, backdrop-filter визуально различим только если элемент реально перекрывает что-то.

Читать дальше
CSS
  • 5 мая 2025
Справочник по новым математическим функциям CSS

Справочник по новым математическим функциям CSS

За последние годы в CSS добавилось много математических функций, для которых не нужен JavaScript. Их можно использовать в анимациях, в графиках для визуализации данных или просто для создания красивых пользовательских интерфейсов.

Эта статья — справочник, который вы можете добавить в закладки и обращаться по мере необходимости. А подробно ознакомиться с работой математических функций можно в интерактивной демонстрации в HTML Academy.

Статья дополняется.

Читать дальше
CSS
  • 28 апреля 2025
CSS Scroll-Driven Animations: что это, зачем нужно и как начать пользоваться

CSS Scroll-Driven Animations: что это, зачем нужно и как начать пользоваться

Раньше, чтобы анимировать что-то при прокрутке, приходилось писать JavaScript. Слушать события scroll, вычислять позиции элементов, руками задавать стили. Это было сложно и работало неэффективно. Но в 2025 в CSS появилась нормальная нативная поддержка скролл-анимаций.

Частичная поддержка есть в Chrome 115+, Edge 115+ и Opera 117+, с флагами — в Firefox 110+. Ждём ещё Safari.

Внимание! Все примеры в этой статье работают только в Chrome 116+.

Читать дальше
CSS
  • 27 апреля 2025
Анимация по любой траектории с offset-path

Анимация по любой траектории с offset-path

У вас же было такое, что ждёте курьера или доставку, а их всё нет и нет? Заходите сайт, обновляете статус, а там «В пути» и больше никакой информации. У нас вот было много раз.

В хороших случаях курьера рисуют прямо на карте, и показывают, где он едет, где проехал, и прямо анимацией можно всё рассмотреть.

Читать дальше
CSS
  • 18 апреля 2025
Автоматическая тёмная тема: новая CSS-функция light-dark()

Автоматическая тёмная тема: новая CSS-функция light-dark()

CSS-функция light-dark() облегчает жизнь при поддержке светлой и тёмной темы. Раньше, чтобы задать разные стили для разных тем, приходилось писать медиа-выражения вроде @media (prefers-color-scheme: dark) и дублировать одни и те же куски стилей с поправками на цвет. Это работало, но выглядело избыточно и громоздко, особенно когда надо было поменять всего один цвет. Для системности создавались CSS-переменные — например, --text-color, значение которой менялось внутри медиавыражения. Всё это работало, но напоминало церемонию ради церемонии.

С light-dark() всё стало проще. Это функция, которая на лету подставляет значение в зависимости от активной темы. Если у пользователя включена светлая тема, функция вернёт первое значение. Если тёмная — второе. Пример: color: light-dark(black, white) — в светлой теме будет чёрный текст, в тёмной — белый. Всё. Никаких переменных, никаких @media. Просто одно свойство и два значения — читаемо, логично, компактно.

Читать дальше
CSS
  • 23 апреля 2024
Псевдокласс :link

Псевдокласс :link

Псевдокласс :link в CSS предназначен для стилизации ссылок, которые ещё не были посещены пользователем. Этот псевдокласс позволяет разработчикам задавать внешний вид для непосещенных ссылок отдельно от тех, по которым пользователь уже переходил, что помогает лучше ориентироваться на странице и повышает удобство использования сайта.

Пример использования псевдокласса :link для стилизации непосещенных ссылок:

a:link {
  color: #007bff;
  text-decoration: none;
}

В данном примере для всех непосещенных ссылок устанавливается синий цвет (#007bff) и убирается подчеркивание. Это делает внешний вид ссылок более аккуратным и одновременно информативным, поскольку пользователь может легко отличить их от уже посещенных (:visited) ссылок.

При работе с :link, важно помнить, что этот псевдокласс должен использоваться в сочетании с псевдоклассом :visited для полной стилизации состояний ссылок. Также рекомендуется определять стили для псевдоклассов :hover и :active, чтобы обеспечить интерактивный и отзывчивый интерфейс.

Пример полного набора стилей для ссылок:

a:link {
  color: #007bff;
  text-decoration: none;
}

a:visited {
  color: #666;
}

a:hover {
  color: #0056b3;
  text-decoration: underline;
}

a:active {
  color: #ff0000;
}

В этом примере задаются различные стили для всех возможных состояний ссылок: :link для непосещённых, :visited для посещённых, :hover при наведении курсора и :active в момент нажатия на ссылку. Такой подход позволяет создать более динамичный и интуитивно понятный интерфейс веб-страницы.

CSS
  • 4 апреля 2024
Селектор потомков (пробел)

Селектор потомков (пробел)

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

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

article p {
  color: #333;
  line-height: 1.6;
}

В данном примере все абзацы (<p>), которые находятся внутри элемента <article>, будут окрашены в темно-серый цвет и получат межстрочный интервал в полтора размера шрифта. Селектор потомков позволяет легко управлять стилем конкретных элементов, сохраняя при этом общую структуру и читаемость кода.

Селектор потомков особенно полезен в следующих случаях:

  1. Структурирование контента: Помогает стилизовать элементы внутри определенных секций или компонентов, не затрагивая похожие элементы в других частях страницы.
  2. Тематическое оформление: Используется для применения уникальных стилей к элементам, расположенным внутри определенных контейнеров, например, для статей, сайдбаров или футеров.
  3. Изоляция стилей: Обеспечивает локальное применение стилей, предотвращая их случайное распространение на другие элементы документа.

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

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

CSS
  • 4 апреля 2024
Псевдокласс :focus

Псевдокласс :focus

Псевдокласс :focus в CSS используется для стилизации элементов, которые получили фокус. Это может быть, например, текстовое поле в форме, к которому пользователь переместил курсор для ввода, или ссылка, выбранная через клавиатурный ввод. Псевдокласс :focus позволяет создать более интерактивный и доступный пользовательский интерфейс, подсвечивая активные или выбранные элементы.

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

input:focus {
  border: 2px solid blue;
  background-color: lightblue;
}

В этом примере для всех текстовых полей (input) при получении фокуса будет изменяться цвет границы на синий и фоновый цвет на светло-синий. Это обеспечивает наглядную обратную связь пользователю о том, какой элемент формы активен в данный момент, улучшая общую пользовательскую доступность и удобство использования интерфейса.

Псевдокласс :focus особенно важен для:

  1. Улучшения доступности: Он помогает пользователям с ограниченными возможностями или теми, кто использует клавиатурный ввод вместо мыши, понимать, какой элемент управления в данный момент активен.
  2. Повышения интерактивности: Визуальное отличие активных элементов делает интерфейс более дружелюбным и понятным для пользователя.
  3. Создания стилистических акцентов: Позволяет добавлять уникальные стилистические особенности для интерактивных элементов интерфейса, подчеркивая их функциональность.

Применение :focus в сочетании с другими псевдоклассами, такими как :hover и :active, позволяет создать комплексное визуальное представление различных состояний элементов управления, делая интерфейс более интуитивно понятным и приятным в использовании.

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

CSS
  • 4 апреля 2024
Селектор по id

Селектор по id

CSS-селектор по идентификатору (id) позволяет стилизовать элементы веб-страницы, которые имеют уникальный идентификатор. Использование селектора по id делает возможным точечное применение стилей к конкретному элементу, не затрагивая другие элементы на странице.

Селектор по id обозначается знаком решетки (#) перед именем идентификатора. Идентификаторы в HTML должны быть уникальными в пределах документа, что делает селектор по id мощным инструментом для стилизации конкретных элементов.

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

<div id="uniqueElement">Этот элемент уникален.</div>
#uniqueElement {
  color: green;
  font-size: 20px;
}

В этом примере элементу <div> с id="uniqueElement" присваиваются стили, делающие текст зеленым и увеличивающие размер шрифта до 20 пикселей. Эти стили будут применены только к этому конкретному элементу благодаря уникальности идентификатора.

Преимущества использования селектора по id:

  1. Точечная стилизация: Селектор по id позволяет применять стили к конкретному элементу, не влияя на другие элементы.
  2. Высокий приоритет: Стили, примененные через селектор по id, имеют более высокий приоритет, чем стили, примененные через классы и теги, что облегчает переопределение стилей.

Важно помнить:

  • Идентификатор должен быть уникальным в пределах всего HTML-документа.
  • Злоупотребление селекторами по id может сделать CSS-код сложным для поддержки, особенно в больших проектах. Рекомендуется использовать их с умом, предпочитая классы для стилизации, когда это возможно.
  • Селекторы по id могут увеличить специфичность CSS-правил, что иногда затрудняет их переопределение.

Использование селектора по id является мощным инструментом в арсенале веб-разработчика, позволяя точечно влиять на стиль отдельных элементов страницы.

CSS
  • 4 апреля 2024
Несколько селекторов через запятую

Несколько селекторов через запятую

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

Пример использования списка селекторов для стилизации заголовков, абзацев и элементов списка:

h1, h2, p, li {
  color: #333;
  font-family: 'Arial', sans-serif;
}

В этом примере все заголовки первого и второго уровней, абзацы и элементы списка (<li>) окрашиваются в темно-серый цвет (#333) и стилизуются шрифтом Arial. Использование списка селекторов позволяет значительно сократить количество кода, необходимого для применения общих стилей к разным элементам.

Применение списка селекторов эффективно во многих ситуациях, включая:

  • Применение базовых стилей текста (цвет, шрифт, размер) к различным типам элементов.
  • Сброс стандартных отступов для элементов списка, параграфов и других блочных элементов.
  • Установка общих стилей для интерактивных элементов, таких как кнопки и ссылки, в различных частях веб-страницы.

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

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

CSS
  • 4 апреля 2024