Паралакс-скролінг зображень за допомогою 3D CSS і JavaScript

29

Від автора: ефекту паралакс-скролінгу можна домогтися безліччю способів, однак я вважаю, що велика їх частина лише імітує глибину зображення. Поглянувши на скрінсейвер з OS X, я зрозумів, що CSS 3D дозволяє по-справжньому змістити зображення на задній план по осі Z, створюючи справжню перспективу і паралакс-ефект під час прокручування зображення вгору і вниз.

Код нашого уроку всього лише прототип, але я вважаю, що він досить цікавий, щоб розповісти вам про нього. Заодно погляньте на демо на CodePen.

Основи

Код починається з одного елемента розмітки, тега div:

Цей блок буде наповнюватися зображеннями, які завантажуються через JavaScript. Насамперед необхідно прописати стилі для блоку DIV і зображень усередині нього:

#parallax-container {
background: #16161d;
margin: 0;
overflow: hidden;
perspective: 1200 px;
height: 100vh;
width: 100vw;
transform-style: preserve-3d;
}
#parallax-container img {
transform-origin: center;
box-shadow: 0 0 12px 12px rgba(0, 0, 0, 0.4);
position: relative;
}

Прокрутка зображень

За методом прогресивного поліпшення необхідно вставити зображення в розмітку, написати CSS код до них і тільки потім за допомогою JS ховати і керувати ними. Так як це всього лише демо, я вибрав самий прямий маршрут. Імена наших зображень створені по одному шаблону wave1.jpg, wave2.jpg… і т. д.), тобто я можу за допомогою JS генерувати імена зображень. Я буду використовувати скрипт нижче поряд з іншими глобальними змінними:

var container = document.getElementById(«parallax-container»),
waveSrc = [],
waves = [],
imgLoc = «»,
j = 0;
for (var i = 0; i < 10; i++) {
waveSrc = imgLoc+»wave»+(i+1)+».jpg»;
}

Мені знадобляться кілька випадкових чисел, які я буду генерувати функції:

function getRandomInRange(min, max) {
return Math.floor(Math.random() * (max — min + 1)) + min;
}

Також мені потрібні посилання завантажуваних зображень і поточна ширина і висота екрану (з умовою, що браузер відкритий на весь екран).

var screenWidth = window.screen.width,
screenHeight = window.screen.height;

Після завантаження зображень і послідовної вставки в контейнер їм задаються властивості .xPlane, .yPlane і zPlane з довільними значеннями. Дані властивості відповідають за позиціонування елементів в 3D просторі. Ми залишили порожніми атрибути alt демо.

function preloadImage(filename){
var img=new Image();
img.onload = function(){
img.xPlane = getRandomInRange(-500, screenWidth — 500);
img.yPlane = getRandomInRange(500, 1000);
img.zPlane = getRandomInRange(300,2000);
img.style = «transform: translate3d(» + img.xPlane +»px,» +
img.yPlane + «px, -» + img.zPlane +»px)»;
container.appendChild(img);
};
imgLoc = «»;
img.src= imgLoc + filename;
img.alt = «»;
waves[j] = img;
j++;
}
function loadImages(){
for (var i = 0; i < waveSrc.length; ++i) {
var filename = waveSrc;
preloadImage(filename);
}
}

І нарешті, ми рухаємо зображення за допомогою функції:

function moveImages(){
waves.forEach(function(image) {
image.yPlane = image.yPlane — 2;
image.style.cssText = «transform: translate3d(» + image.xPlane+»px,
«+ image.yPlane+»px, -» + image.zPlane + «px); z-index:» + image.zIndex;
});
window.requestAnimationFrame(moveImages);
}

Щоб все запрацювало, в кінці скрипта необхідно викликати відповідні функції:

loadImages();
window.addEventListener. («load»,
function() {
window.requestAnimationFrame(moveImages);
});

Поліпшення

Наш код – це прототип, і він дещо грубуватий. В нього можна внести очевидні покращення:

Зараз наш скрипт продовжує працювати, коли всі зображення зникають у верхній частині контейнера, тобто він працює нескінченно. В ідеалі, скрипт повинен вирізати зображення з початку масиву після їх зникнення і вставляти їх в самий низ екрану.

Як ні парадоксально, краще зробити розташування зображень більш передбачуваним. Прямо зараз у нашому демо зображення може з’явитися точно за іншим зображенням або майже на одному рівні з ним (тобто обидва зображення будуть рухатися з однією швидкістю). Щоб уникнути подібних ситуацій, мені знадобилося б порівнювати значення розташування нових зображень з тими, що вже прописані в масиві. Якщо значення дуже близькі, мені довелося б генерувати нове випадкове значення.

Ми створили техніку з автоматичною прокруткою. Якщо ви хочете прив’язати рух зображень до позиції скроллбара на сторінці, ви можете змінювати розташування зображень за window.scrollY.