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

На чём делать параллакс-эффект: CSS или JavaScript
Параллакс при прокрутке страниц создают с помощью 3D трансформаций: transform-style: preserve-3d, perspective, transform: 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 Scroll, parallax JS или rellax. С их помощью можно управлять направлением движения элементов, фиксировать слайды при прокрутке, создавать эффект «спешки» или «задержки» анимации.
Узнать больше
«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.
Читать дальше

CSS font-palette: управление цветами шрифтов
Свойство font-palette
позволяет выбрать одну из цветовых палитр, встроенных в цветной шрифт, или создать свою. При использовании — оно задаёт преобладающую окраску глифов, и свойство color
уже не влияет.
В свою очередь, цветной шрифт — это шрифт, в котором глифы содержат встроенную информацию о цвете. В отличие от обычных векторных шрифтов (TrueType, OpenType), где цвет задаётся снаружи с помощью CSS-свойства color, в цветном шрифте сами глифы уже закодированы с цветными деталями — например, несколько заливок, градиенты, обводки, изображения.
Альтернативные цветовые палитры шрифта Nabla (Typearture, Google Fonts)
Свойство вошло в Baseline в статусе widely available в мае 2025 года. Теперь его можно использовать в проектах и не переживать о поддержке.
- 18 июня 2025

Как анимировать CSS Grids без JavaScript
Grid Layout — одна из самых зрелых технологий в CSS. Он давно решает задачи макета гораздо лучше, чем float
, flex
и position
. Но долгое время у него была одна неочевидная граница: анимация размеров сетки.
Да, grid-template-columns
и grid-template-rows
существовали с самого начала появления гридов. Да, они были мощными. Но плавно менять их было нельзя — браузеры просто прыгали между состояниями. Анимация сетки оставалась мечтой.
Ситуация изменилась c 27 апреля 2025 года. Анимация grid-template-columns
и grid-template-rows
вошла в baseline — это означает, что теперь она официально поддерживается всеми современными браузерами. Без флагов. Без хака с display: contents
. Просто работает.
- 1 июня 2025

Все единицы измерения в CSS от лучших к худшим
CSS использует разные единицы измерения для задания размеров, отступов, шрифтов и других свойств. Разделяют абсолютные и относительные единицы. Понимание различий между ними — фундаментальная основа адаптивной, масштабируемой и удобной в поддержке вёрстки.
Абсолютные:
px
— пикселиcm
— сантиметрыmm
— миллиметрыin
— дюймыpt
— типографские пунктыpc
— пика
Относительные:
z%
— процент от родителяem
— от размера шрифта родителяrem
— от размера шрифта корняvw
— 1% от ширины вьюпортаvh
— 1% от высоты вьюпортаvmin
/vmax
— минимальное/максимальное из vw и vhfr
— доля пространства в грид-сеткеch
— ширина символа «0»ex
— высота строчной буквы «x»
Примеры ниже снабжены пояснениями из практики, с фокусом на применение в реальных проектах.
- 30 мая 2025

Как размыть фон под элементом с помощью 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
визуально различим только если элемент реально перекрывает что-то.
- 5 мая 2025

Справочник по новым математическим функциям CSS
За последние годы в CSS добавилось много математических функций, для которых не нужен JavaScript. Их можно использовать в анимациях, в графиках для визуализации данных или просто для создания красивых пользовательских интерфейсов.
Эта статья — справочник, который вы можете добавить в закладки и обращаться по мере необходимости. А подробно ознакомиться с работой математических функций можно в интерактивной демонстрации в HTML Academy.
Статья дополняется.
- 28 апреля 2025

CSS Scroll-Driven Animations: что это, зачем нужно и как начать пользоваться
Раньше, чтобы анимировать что-то при прокрутке, приходилось писать JavaScript. Слушать события scroll
, вычислять позиции элементов, руками задавать стили. Это было сложно и работало неэффективно. Но в 2025 в CSS появилась нормальная нативная поддержка скролл-анимаций.
Частичная поддержка есть в Chrome 115+, Edge 115+ и Opera 117+, с флагами — в Firefox 110+. Ждём ещё Safari.
Внимание! Все примеры в этой статье работают только в Chrome 116+.
- 27 апреля 2025

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

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

Псевдокласс :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
в момент нажатия на ссылку. Такой подход позволяет создать более динамичный и интуитивно понятный интерфейс веб-страницы.
- 4 апреля 2024

Селектор потомков (пробел)
Селектор потомков в CSS используется для выбора элементов, которые являются потомками другого элемента в структуре документа. Этот селектор обозначается простым пробелом между двумя селекторами и позволяет применить стили к элементам, находящимся внутри других элементов, независимо от глубины их вложенности.
Пример использования селектора потомков:
article p {
color: #333;
line-height: 1.6;
}
В данном примере все абзацы (<p>
), которые находятся внутри элемента <article>
, будут окрашены в темно-серый цвет и получат межстрочный интервал в полтора размера шрифта. Селектор потомков позволяет легко управлять стилем конкретных элементов, сохраняя при этом общую структуру и читаемость кода.
Селектор потомков особенно полезен в следующих случаях:
- Структурирование контента: Помогает стилизовать элементы внутри определенных секций или компонентов, не затрагивая похожие элементы в других частях страницы.
- Тематическое оформление: Используется для применения уникальных стилей к элементам, расположенным внутри определенных контейнеров, например, для статей, сайдбаров или футеров.
- Изоляция стилей: Обеспечивает локальное применение стилей, предотвращая их случайное распространение на другие элементы документа.
Применение селектора потомков упрощает создание модульной и легко поддерживаемой структуры стилей, позволяя разработчикам более точно и гибко управлять внешним видом веб-страницы.
Однако, важно соблюдать баланс и избегать слишком глубокой вложенности селекторов, так как это может усложнить поддержку и оптимизацию кода. Рекомендуется использовать селектор потомков с умом, ориентируясь на поддержание чистоты и простоты структуры CSS.
- 4 апреля 2024