Параллакс в веб-дизайне: как сделать эффект на CSS и JavaScript

Параллакс в веб-дизайне: как сделать эффект на CSS и JavaScript Полезное

Параллакс (parallax) в веб-дизайне — это прием, при котором несколько слоев страницы (фон, картинки, текст) смещаются с разной скоростью в ответ на скролл или движение мыши. Дальний слой движется медленнее ближнего, и за счет этого возникает ощущение глубины на плоском экране. Ниже разберем, как работает эффект, как собрать его на чистом CSS и на JavaScript, где он уместен, и почему доступность (prefers-reduced-motion) тут не опция, а обязательный шаг.

Название пришло из астрономии: параллакс — это видимое смещение объекта относительно фона при смене точки наблюдения. В интерфейсе роль «смены точки наблюдения» играет скролл или курсор.

Как работает эффект: слои и скорость

Минимальный параллакс собирается из трех частей:

  • дальний слой (фон), который смещается медленно или стоит на месте;
  • ближний слой (контент, текст, карточка), который смещается быстрее;
  • триггер движения — прокрутка страницы (scroll) или перемещение курсора (mousemove).

Разница скоростей и создает глубину. Чем сильнее отстает дальний слой от ближнего, тем «глубже» выглядит сцена. Важно не путать параллакс с обычной анимацией появления при скролле: если объект просто выезжает или меняет прозрачность, но не смещается относительно других слоев, это не параллакс, а scroll-анимация.

Способы реализации: что выбрать

Есть три рабочих подхода. У каждого своя область применения, и выбирать стоит по задаче, а не по «модности».

Способ Как работает Когда брать Ограничения
background-attachment: fixed Фоновая картинка блока не прокручивается вместе с контентом Простой геройский блок, один фон Часто игнорируется мобильными браузерами; конфликтует с overflow и transform у предков
3D-трансформации на чистом CSS Слои сдвигаются по оси Z в контейнере с perspective; скорость задает глубина Многослойный скролл-параллакс, нужна плавность Требует контейнер-скролл; логику скорости задает математика translateZ/scale
JavaScript (scroll/mousemove) Скрипт читает позицию и вручную двигает слои через transform Реакция на курсор, сложные сценарии Легко уронить производительность; нужен requestAnimationFrame и учет доступности

Общее правило для всех трех: двигать слои надо через свойство transform (его умеет ускорять видеокарта), а не через top/left/margin — последние заставляют браузер пересчитывать раскладку на каждом кадре и дают рывки.

Способ 1: фон на background-attachment: fixed

Самый короткий вариант. Фон блока фиксируется, а контент проезжает поверх него.

.parallax-hero {
  min-height: 100vh;
  background-image: url("hero.jpg");
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
}
<section class="parallax-hero">
  <h2>Заголовок поверх фиксированного фона</h2>
</section>

Результат: при прокрутке текст движется, а фоновая картинка остается на месте — возникает эффект глубины. Граница способа: многие мобильные браузеры (в частности Safari на iOS) намеренно не поддерживают background-attachment: fixed из-за нагрузки, и там фон просто прокрутится как обычно. Эффект тут не сломается фатально, но и не покажется. Это упрощенный параллакс на один слой, а не полноценная многослойная сцена.

Способ 2: многослойный параллакс на чистом CSS

Более честный параллакс без JavaScript строится на 3D-трансформациях. Идея: задать контейнеру перспективу и прокрутку, а слои увести по оси Z на разную глубину.

<div class="parallax">
  <div class="layer layer-back">Дальний слой</div>
  <div class="layer layer-base">Контент страницы</div>
</div>
.parallax {
  height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;      /* прокрутка живет внутри контейнера */
  perspective: 1px;      /* включаем 3D-пространство */
}
.layer {
  position: absolute;
  inset: 0;
}
.layer-back {
  transform: translateZ(-1px) scale(2);
}
.layer-base {
  transform: translateZ(0);
}

Разберем по строкам. perspective: 1px на контейнере создает 3D-сцену, где ось Z отвечает за расстояние до наблюдателя. Слой с translateZ(-1px) уходит вглубь и при прокрутке смещается медленнее переднего — это и есть параллакс.

Отодвинутый слой становится визуально меньше, поэтому его надо вернуть к нужному размеру через scale. Коэффициент считается по формуле (perspective - translateZ) / perspective. Здесь это (1 - (-1)) / 1 = 2, отсюда scale(2). Если поставить translateZ(-2px), масштаб станет scale(3). Прокрутка при этом должна жить внутри .parallax (overflow-y: auto), иначе перспектива не сработает.

Способ 3: параллакс по движению мыши на JavaScript

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

<div class="scene" id="scene">
  <div class="card" data-speed="2">Ближний слой</div>
  <div class="card" data-speed="5">Дальний слой</div>
</div>
const scene = document.getElementById("scene");
const layers = scene.querySelectorAll(".card");
let frame = null;

scene.addEventListener("mousemove", (event) => {
  const rect = scene.getBoundingClientRect();
  // смещение курсора от центра сцены, диапазон примерно от -0.5 до 0.5
  const dx = (event.clientX - rect.left) / rect.width - 0.5;
  const dy = (event.clientY - rect.top) / rect.height - 0.5;

  // откладываем обновление до следующего кадра, чтобы не грузить браузер
  cancelAnimationFrame(frame);
  frame = requestAnimationFrame(() => {
    layers.forEach((layer) => {
      const speed = Number(layer.dataset.speed) || 1;
      layer.style.transform =
        "translate(" + dx * speed * 20 + "px," + dy * speed * 20 + "px)";
    });
  });
});

Что происходит: dx и dy — это относительное смещение курсора от центра сцены, от -0.5 до 0.5. Каждый слой сдвигается на величину, умноженную на свою data-speed, поэтому «дальний» слой со скоростью 5 отъезжает сильнее ближнего. Результат: при движении мыши слои разъезжаются, создавая глубину.

Обертка в requestAnimationFrame важна: событие mousemove срабатывает десятки раз в секунду, и без нее браузер будет пересчитывать позиции чаще, чем успевает рисовать кадры. Отсюда типовой симптом плохого параллакса — «рывки» и подвисание скролла. Если видите такое, первым делом проверьте, что двигаете слои через transform и группируете обновления по кадрам.

Доступность: prefers-reduced-motion обязателен

Крупные параллакс-сцены и резкие движения при скролле вызывают у части пользователей укачивание, головокружение и дискомфорт — это связано с вестибулярными нарушениями. Поэтому в системах есть настройка «уменьшить движение», и сайт обязан ее уважать.

На стороне CSS движение отключают через медиазапрос:

@media (prefers-reduced-motion: reduce) {
  .layer-back {
    transform: none;
  }
  .parallax {
    overflow: visible;
    perspective: none;
  }
}

В JavaScript ту же настройку читают перед тем, как вешать обработчики:

const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
if (!reduceMotion.matches) {
  // навешиваем параллакс только если пользователь не просил убрать движение
  scene.addEventListener("mousemove", onMouseMove);
}

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

Плюсы, минусы и когда эффект уместен

Плюсы: параллакс повышает вовлечение и удержание на промо-страницах, помогает выделить ключевой объект (например, продукт на переднем плане) и делает лендинг заметнее среди однотипных конкурентов.

Минусы и риски:

  • производительность: неаккуратная реализация грузит отрисовку и дает рывки, особенно на слабых устройствах;
  • доступность: без prefers-reduced-motion эффект вредит части аудитории;
  • мобильные: сенсорный скролл и слабая поддержка background-attachment: fixed часто ломают задумку;
  • перегруз: если весь сайт «дышит», это отвлекает от контента и мешает конверсии.

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

Выводы

  • Параллакс — это смещение слоев страницы с разной скоростью при скролле или движении курсора, что создает иллюзию глубины.
  • Есть три рабочих способа: background-attachment: fixed (просто, но капризно на мобильных), 3D-трансформации на чистом CSS (плавно, без скриптов) и JavaScript (для реакции на курсор и сложных сценариев).
  • Двигать слои надо через transform, а обновления в JS группировать через requestAnimationFrame — иначе будут рывки.
  • Поддержка prefers-reduced-motion обязательна: при включенной настройке движение отключается, контент остается читаемым.
  • Эффект уместен на промо и сторителлинге, но вреден там, где важна скорость работы с интерфейсом.

Где применяется / связь с практикой

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

Освойте тему на практике

Разложить верстку и CSS-эффекты по полочкам помогает курс HTML/CSS: там разбирают блочную модель, позиционирование, трансформации и адаптивность на практике. Посмотреть формат и уровень занятий можно на открытых уроках Otus — это бесплатно и помогает понять, подходит ли тема.

FAQ

Параллакс тормозит скролл — что делать?
Проверьте, что слои двигаются через transform, а не через top/margin, и что в JS обновления обернуты в requestAnimationFrame. Также помогает уменьшить число анимируемых слоев и добавить свойство will-change: transform для тяжелых элементов.

Почему фиксированный фон не работает на телефоне?
Многие мобильные браузеры намеренно не поддерживают background-attachment: fixed из-за нагрузки на отрисовку. Для мобильных лучше собрать параллакс на 3D-трансформациях или отключить эффект и показать статичный фон.

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

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)