[Перевод] Как сделать многослойную Parallax иллюстрацию на CSS & JavaScript

image
Рисунок используемый для parallax эффекта. Автор Patryk Zabielski
Привет друзья, я покажу вам как создать простою многослойную иллюстрацию с глубиной, которая переходит к контенту. Мы будем использовать метод, в котором необходим только css и чистый JS (coffeescript) (Никаких jQuery!).
Этот урок для начинающих, с начальным знанием JS и CSS, так что я буду объяснять большинство вещей и ссылаться на внешние источники.
Финальное демо

Подготовим илюстрация


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

image
Визуализированный концепт слоев в 3D пространстве

Нам нужно разделить картину на несколько png файлов с прозрачным фоном, что даст нам возможность создать чувство глубины.

Слои на заднем плане будут двигаться медленнее, чем те, что на переднем, что даст нам эффект глубины.

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

image
На картинке справа есть незаметная линия, которая даст нам лучший переход в следующую секцию

Начнем кодить


Подготовление
Что вам потребуется:

  • Свежий проект в Codepen (Если вы хотите следовать коду ниже, то не забудьте изменить HTML на HAML, CSS на SCSS и JS на Coffeescript, в настройках Codepen)
  • Начальные знания HAML & Sass (SCSS)
  • Базовое понимание Javascript и Coffeescript (Если у вас все еще плохо с этим — я рекомендую «Javascript & jQuery» by Jon Duckett) Если вам не хочется работать с Coffeescript, то вы можете автоматически конвертировать его в JS и вставить фрагменты кода ниже чтобы получить чистый JS
  • Ваши иллюстрация/фото разделенная на несколько png слоев


Давайте начнем с HTML структуры. Мы сделаем контейнер-родитель и дадим ему ID 'hero'. Потом мы добавим несколько div, с классом 'layer' и data-type атрибутом со значением 'parallax'.

#hero
    .layer{"data-type” => "parallax”}
    .layer{"data-type” => "parallax”}
    .layer{"data-type” => "parallax”}
    .layer{"data-type” => "parallax”}
    .layer{"data-type” => "parallax”}


Добавим базовых стилей. Начнем с #hero. Я установил высоту иллюстрации 800 px

#hero {
  height: 800px;
  overflow: hidden;
  position: relative;
}


Теперь, перейдем к стилизации повторяющего класса слоев. У каждого из них будет одинаковая высота, как у #hero и позиционирование, и мы добавим position: fixed

.layer {
  background-position: bottom center;
  background-size: auto;
  background-repeat: no-repeat;
  width: 100%;
  height: 800px;
  position: fixed;
  z-index: -1;
}


Следующая вещь, которую мы хотим сделать это добавить картинки, которая мы подготовили до этого. Мы создадим еще несколько классов, по одному для каждого слоя. После чего добавим ссылку на картинку внутри свойства background-image.

.layer-01 {
   background-image: url('ссылка на картинку');
}
.layer-02 {
   background-image: url('ссылка на картинку');
}
// и т.д.


Не забудьте обновить HTML и назначить классы к нужным div в нашем порядке, первым слой это задний фон, следующие слои будут накладывать поверх друг-друга

#hero
  .layer.layer-01{"data-type” => "parallax”}
  .layer.layer-02{"data-type” => "parallax”}
  .layer.layer-03{"data-type” => "parallax”}
  .layer.layer-04{"data-type” => "parallax”}
  .layer.layer-05{"data-type” => "parallax”}


Время JavaScript
Добавим методом, который будет проверить если пользователь начал прокручивать страницу вниз.

window.addEventListener ‘scroll’, (event)


EventTarget.addEventListener () метод регистрирует слушателя на EventTarget. event target может быть элемент в document, сам document, объект Window или любой объект поддерживающий события (такие как XMLHttpRequest)


Сохраним количество пикселей, которое проскролено вертикально от начала страницы в переменную topDistance. Чтобы сделать это, будем использовать свойство pageYOffset

window.addEventListener ‘scroll’, (event) ->
  topDistance = @pageYOffset


После этого, мы выберем все слои в нашей илюстрации и сохраним их в переменную layers. Для этого мы будем использоваться методом querySelectorAll и data атрибут внутри элементов HTML, который мы установили до этого.

window.addEventListener ‘scroll’, (event) ->
  topDistance = @pageYOffset
  layers = document.querySelectorAll("[data-type='parallax']")


Следующее что мы сделаем, это пройдемся циклом через все слои и применим свойство transform к каждому из них. Но перед этим, мы укажем еще одну вещь внутри нашего HTML файла, атрибут data-depth. Он даст нам возможность контролировать как быстро элемент будет двигаться, давайте не будем глубоко углубляться в значения, мы вернемся к этому позже.

#hero
  .layer.layer-01{"data-type” => "parallax”, "data-depth" => "0.10"}
  .layer.layer-02{"data-type” => "parallax”, "data-depth" => "0.20"}
  .layer.layer-03{"data-type” => "parallax”, "data-depth" => "0.50"}
  .layer.layer-04{"data-type” => "parallax”, "data-depth" => "0.80"}
  .layer.layer-05{"data-type” => "parallax”, "data-depth" => "1.00"}


Чтобы пройтись через все элементы, мы будем использоваться цикл for. Начнем наш цикл с создания переменной, где мы будем хранить наши слои. После чего возьмем значение из data-depth атрибута, который мы указали внутри нашего HTML. Далее, мы вычислим передвижение слоев, умножив дистанцию скрола от начала страницы на значение атрибута data-depth данного слоя. Элемент со значение 1.0 будет двигаться нормально с остальной страницей, вы можете воспринимать его, как элемент с выключенным parallax.

Последнее что мы сделаем, это обновим окончательное значение движения для параметра transform translate3d слоя, чтобы сделать это мы будем использовать свойство style вместе со всеми вендорными префиксами для transform.

Чтобы код был более читаем и DRY, мы сохраним параметр translate3d в переменную translate3d

for layer in layers
  depth = layer.getAttribute(‘data-depth’)
  movement = -(topDistance * depth)
  translate3d = 'translate3d(0, ' + movement + 'px, 0)'
  layer.style['-webkit-transform'] = translate3d
  layer.style['-moz-transform'] = translate3d
  layer.style['-ms-transform'] = translate3d
  layer.style['-o-transform'] = translate3d
  layer.style.transform = translate3d


Теперь когда мы указали data-depth=»1.00» элемент будет двигаться вместе со страницей, как обычный элемент без parallax эффекта. Все значение меньше чем 100 будут иметь эффект parallax.Телефоны
Для телефонов мы отключим parallax версию и заменим ее на статичную картинку, чтобы сохранить производительность. Чтобы сделать это, создадим новый div ниже нашего div #hero, с id hero-mobile и применим к нему display: none вместе с параметрами background и height.

#hero-mobile {
  display: none;
  background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/272781/full_illustration.png") no-repeat center bottom / cover;
  height: 320px;
}


Чтобы показывать его вместо parallax, будем использовать media query и применять параметр display: none к десктопной версии, переопределяя наш display: none на display: block для #hero-mobile.

@media all and (max-width: 640px) {
  #hero {
     display: none;
  }
  #hero-mobile {
     display: block;
  }
}


Финальный код

© Habrahabr.ru