Задача: разработать параллакс эффект движущейся толпы, реагирующей на передвижение курсора мыши без бустовых библиотек вроде rellax.js.
Для начала, вот что должно получиться:
Мы с вами уже реализовывали простой параллакс эффект в предыдущей статье. Если не видели - вот ссылка.
В отличие от предыдущего примера, мы не будем использовать готовую библиотеку, а значит придется немного поколдовать над математикой.
Шаг 1 - Подготовка
Для начала нам нужно найти и подготовить изображение. Я пользовался бесплатным стоком Unsplash и искал в нем картинки по запросу crowd (толпа) и concert (концерт). Вы можете выбрать и скачать любое понравившееся изображение, но для упрощения дальнейшей работы воспользуйтесь парой советов:
- Позиция камеры (точка, откуда осуществлялась съемка) должна находиться за спинами людей.
- Силуэты людей должны быть различимы. Если возьмете изображение, на котором людей практически не видно - будет сложнее вырезать их и развести по разным слоям в фотошопе.
- Чем больше места (по высоте) на изображении занимает толпа, тем эффектнее получится результат.
В остальном ни в чем себя не ограничивайте: выбирайте то, что понравится.
Шаг 2 - Магия фотошопа
Итак, у вас есть подходящее изображение. Если все еще нет - вернитесь к первому шагу.
Открываем в изображение в фотошопе или любом другом редакторе. И начинаем методично вырезать людей ряд за рядом.
Берем инструмент лассо и обводим контуры людей, находящихся ближе всего к нам (к позиции камеры). Стараемся чтоб в итоге получилось выделение от левого до правого края изображения примерно одинаковой высоты. У меня получилось вот так:
У вас, конечно, получится аккуратнее)
Вырезаем выделенную область и помещаем на новый слой. Заливаем фоновым цветом прозрачные области ниже вырезанного фрагмента. Прозрачные области выше оставляем как есть. Повторяем действия.
В итоге у меня получилось 4 слоя. Самым нижним будет сцена, а дальше слои с людьми: сверху те, что находятся на изображении ближе к камере, снизу те, что находятся дальше от камеры (ближе к сцене):
Вот так это выглядит в фотошопе:
А вот так наглядно.
Надеюсь проблем с этим не возникло, но если что - добро пожаловать в комментарии:)
Последним этапом сохраняем слои как отдельные изображения в png формате (нам важна прозрачность).
Шаг 3 - Разметка и стили (html и css)
С html все просто: контейнер, в нем под каждый "слой" - свой div, в дивах изображения:
<div class="container"> <div id="scene" class='parallax' data-speed="-4"> <img src="https://ydmitry.ru/upload/blog/crowd/scene.png"> </div> <div id="crowd-first" class='parallax'> <img src="https://ydmitry.ru/upload/blog/crowd/crowd-first.png"> </div> <div id="crowd-second" class='parallax' data-speed="-2"> <img src="https://ydmitry.ru/upload/blog/crowd/crowd-second.png"> </div> <div id="crowd-third" class='parallax' data-speed="-3"> <img src="https://ydmitry.ru/upload/blog/crowd/crowd-third.png"> </div> </div>
Data-speed мы будем использовать для корректировки скорости движения блоков.
По стилям. Для контейнера задаем ширину и высоту по размеру изображения, а также overflow: hidden чтобы содержимое обрезалось, когда мы будем его двигать. Ну и position: relative, относительно этого контейнера мы будем позиционировать все вложенные блоки. Все остальные стили - по вкусу. В моем случае это центрирование и задание цвета фона.
.container {
position: relative;
bottom: 0;
background: #1f2c2c;
height: 800px;
width: 1200px;
margin: 0 auto;
overflow: hidden;
}
Всем блокам под изображения задаем класс parallax. Им ставим position: absolute. Блокам с изображениями проставляем z-index.
.parallax {
position: absolute;
}
#scene {
z-index: 100;
}
#crowd-third {
z-index: 200;
}
#crowd-second {
z-index: 300;
}
#crowd-first {
z-index: 400;
}
Шаг 4 - JavaScript (джейквайри детектед)
Как всегда, код оформлен для лучшего понимания, кто захочет - отрефакторит для продакшена :)
$(document).ready(function(){Вот и все. Весь код и параллакс в действии можно посмотреть на codepen.
var elem = $('.container'), // Контейнер, в котором будем проводить анимацию
pos = elem.offset(), // Позиция элемента
elem_left = pos.left, // Слева
elem_top = pos.top, // Сверху
elem_width = elem.width(), // Ширина элемента
elem_height = elem.height(), // Высота элемента
x_center, // Координаты центра по оси X
y_center; // Координаты центра по оси Y
// Обрабатываем событие перемещения курсора мыши
$('.container').mousemove(function(e){
// Определяем центр элемента (формула легко гуглится)
x_center = ( elem_width / 2 ) - ( e.pageX - elem_left );
y_center = ( elem_height / 2 ) - ( e.pageY - elem_top );
// Проходим по всем блокам с изображениями)
$('.parallax').each(function(){
var speed = $(this).attr('data-speed'), // Определяем скорость
xPos = Math.round(-1*x_center/20*speed),// Высчитываем позицию по оси X, движения будут инвертированы (-1). Формула подбиралась на глаз
yPos = Math.round(y_center/20*speed); // Высчитываем позицию по оси Y
// Перемещение по оси Y делаем до определенной точки, потом перемещение останавливаем
if (yPos < 0)
yPos = -2*speed;
// Непосредственно перенос
$(this).css('transform', 'translate3d('+xPos+'px, '+yPos+'px, 0px)');
});
});
});