Как сделать такой parallax эффект?

181
18 марта 2022, 21:00

Как сделать такой эффект, как на сайте https://www.fotonaut.cz/en/ ? Интересует поведение пилюль (таблеток), если присмотреться, они как бы живут своей жизнью, двигаются в независимости от движения мыши. И двигаются даже когда мышь не двигается. Интересует именно этот эффект. Кто-нибудь знает как это сделать?)) Спасибо!!!

Answer 1

Что-то такое получилось:

// функция линейной интерполяции 
let lerp = (a, b, val) => a + val * (b - a);   
// генератор псевдослучайных чисел 
let rand = n => (Math.sin(n)*43758.5453123)%1;  
// одномерный шум 
let noise = p => lerp(rand(Math.floor(p)), rand(Math.floor(p) + 1.0), p%1); 
// слои, принимающие участие в параллакс эффекте 
let layers = document.querySelectorAll('.parallax'); 
// массив с состояниями слоёв 
let offsets = [...layers].map(l => ({x:0, y:0, X:0, Y:0})); 
 
// слушатель положения курсора 
addEventListener('mousemove', e => { 
  let dx = innerWidth/2 - e.x; // дельта по X от центра экрана 
  let dy = innerHeight/2 - e.y; // дельта по X от центра экрана 
  offsets.forEach((layer, i) => { // для каждого слоя поменяем "целевое" положение 
    layer.X = (1 + i) * dx * 0.1; // положение слоя по X 
    layer.Y = (1 + i) * dy * 0.1; // положение слоя по Y 
  }); 
}) 
 
requestAnimationFrame(draw); // говорим браузеру что надо нарисовать кадр 
 
// функция, которая рисует один кадр, ее аргумент - время с начала анимации в мс 
function draw(t) { 
  offsets.forEach((layer, i) => {         // для каждого слоя,  
    layer.x += (layer.X - layer.x) * 0.1; // двигаемся в сторону целевого положения по Х 
    layer.y += (layer.Y - layer.y) * 0.1; // и по Y 
    let x = layer.x + noise((1e5+t/9e3)*(i+1))*33; // + значение шума от времени по Х 
    let y = layer.y + noise((1e7+t/9e3)*(i+1))*22; // и по Y 
    layers[i].style.transform = `translate(${x}px,${y}px)`; // двигаем слой 
  }) 
  requestAnimationFrame(draw); // говорим браузеру что надо-бы нарисовать еще один кадр 
}
.parallax { 
  position: fixed; 
}
<div class="parallax"> 
  <img src="https://picsum.photos/id/41/900/300" 
       style="margin:-50px"> 
</div> 
<div class="parallax"> 
  <img src="https://picsum.photos/id/23/150" 
       style="margin:20px"> 
</div> 
<div class="parallax"> 
  <img src="https://picsum.photos/id/43/80" 
       style="margin:40px"> 
</div>

Answer 2

Вот как вариант. Конечно, на SO есть товарищи, которые могут реализовать это гораздо лучше. Мне и самому хотелось бы увидеть такие решения.

var currentX = ''; 
var currentY = ''; 
var movementConstant = 0.05; 
$(document).mousemove(function(e) { 
  if (currentX == '') currentX = e.pageX; 
  var xdiff = e.pageX - currentX; 
  currentX = e.pageX; 
  if (currentY == '') currentY = e.pageY; 
  var ydiff = e.pageY - currentY; 
  currentY = e.pageY; 
  $('.parallax_contanier div').each(function(i, el) { 
    var movement = (i + 1) * (xdiff * movementConstant); 
    var movementy = (i + 1) * (ydiff * movementConstant); 
    var newX = $(el).position().left + movement; 
    var newY = $(el).position().top + movementy; 
    $(el).css('left', newX + 'px'); 
    $(el).css('top', newY + 'px'); 
  }); 
});
body, 
html { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  overflow: hidden; 
  width: 100vw; 
  height: 100vh; 
  background: url('https://i.imgur.com/SPbeVMa.jpg') center center no-repeat; 
  background-size: cover; 
} 
 
.parallax { 
  position: absolute; 
  top: 0; 
  left: 0; 
  width: 30%; 
  height: 40%; 
  opacity: 0.5; 
} 
 
.layer1 { 
  top: 20%; 
  left: 10%; 
  background-color: red; 
} 
 
.layer2 { 
  top: 40%; 
  left: 60%; 
  background-color: blue; 
} 
 
.random { 
  position: absolute; 
  top: 0; 
  left: 0; 
  width: 100px; 
  height: 100px; 
} 
 
.random1 { 
  border-radius: 100%; 
  top: 30%; 
  left: 20%; 
  background-color: green; 
  animation: moveY 15s linear 0s infinite alternate; 
} 
 
.random2 { 
  top: 60%; 
  left: 50%; 
  background-color: gold; 
  animation: moveX 15s linear 0s infinite alternate; 
} 
 
@keyframes moveX { 
  0% { 
    top: 0; 
    left: 0; 
    transform: rotate(0deg); 
  } 
  20% { 
    top: 30%; 
    left: 20%; 
    transform: rotate(72deg); 
  } 
  40% { 
    top: 5%; 
    left: 40%; 
    transform: rotate(144deg); 
  } 
  60% { 
    top: 30%; 
    left: 60%; 
    transform: rotate(216deg); 
  } 
  80% { 
    top: 4%; 
    left: 70%; 
    transform: rotate(288deg); 
  } 
  100% { 
    top: 2%; 
    left: 80%; 
    transform: rotate(360deg); 
  } 
} 
 
@keyframes moveY { 
  0% { 
    top: 0%; 
    left: 30%; 
  } 
  20% { 
    top: 20%; 
    left: 40%; 
  } 
  40% { 
    top: 45%; 
    left: 30%; 
  } 
  60% { 
    top: 60%; 
    left: 5%; 
  } 
  80% { 
    top: 70%; 
    left: 30%; 
  } 
  100% { 
    top: 80%; 
    left: 20%; 
  } 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> 
<div class="parallax_contanier"> 
  <div class="parallax layer1"></div> 
  <div class="parallax layer2"></div> 
</div> 
 
<div class="random_contanier"> 
  <div class="random random1"></div> 
  <div class="random random2"></div> 
</div>

Answer 3

Хотелось бы всё же дополнительно добавить вариант, в котором для передвижения элементов в независимости от движения мыши вместо @keyframes используется очень интересное решение от @hu-fo (за что ему спасибо!).

//Решение @hu-fo. Передвижение элементов в независимости от движения мыши 
var items = document.querySelectorAll('.layer__item'); 
var layer = document.querySelector('.layer'); 
items.forEach(item => requestAnimationFrame(() => move(item))); 
function move(el) { 
  var s = Math.random() > 0.5 ? 1 : -1; 
  var x = s * (Math.random() * 40); 
  var y = s * (Math.random() * 40); 
  var td = Math.random() * 3 + 1; 
  el.style.transitionDuration = `${td}s`; 
  el.style.transform = `translate3d(${x}px, ${y}px, 0)`; 
  setTimeout(function() { 
    requestAnimationFrame(() => move(el)); 
  }, td * 1000); 
} 
//Передвижение элементов в зависимости от движения мыши 
var currentX = ''; 
var currentY = ''; 
var movementConstant = 0.05; 
$(document).mousemove(function(e) { 
  if (currentX == '') currentX = e.pageX; 
  var xdiff = e.pageX - currentX; 
  currentX = e.pageX; 
  if (currentY == '') currentY = e.pageY; 
  var ydiff = e.pageY - currentY; 
  currentY = e.pageY; 
  $('.parallax_contanier div').each(function(i, el) { 
    var movement = (i + 1) * (xdiff * movementConstant); 
    var movementy = (i + 1) * (ydiff * movementConstant); 
    var newX = $(el).position().left + movement; 
    var newY = $(el).position().top + movementy; 
    $(el).css('left', newX + 'px'); 
    $(el).css('top', newY + 'px'); 
  }); 
});
body, 
html { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  overflow: hidden; 
  width: 100vw; 
  height: 100vh; 
  background: url('https://i.imgur.com/SPbeVMa.jpg') center center no-repeat; 
  background-size: cover; 
} 
 
.parallax { 
  position: absolute; 
  top: 0; 
  left: 0; 
  width: 30%; 
  height: 40%; 
  opacity: 0.5; 
} 
 
.layer1 { 
  top: 20%; 
  left: 10%; 
  background-color: red; 
} 
 
.layer2 { 
  top: 40%; 
  left: 60%; 
  background-color: blue; 
} 
 
.layer { 
  position: absolute; 
  width: 100%; 
  height: 100%; 
  list-style: none; 
} 
 
.layer__item { 
  position: absolute; 
  height: 30px; 
  width: 30px; 
  border-radius: 100%; 
} 
 
.layer__item:nth-child(1) { 
  left: 70%; 
  top: 20%; 
  background-color: gold; 
} 
 
.layer__item:nth-child(2) { 
  left: 20%; 
  top: 20%; 
  background-color: green; 
} 
 
.layer__item:nth-child(3) { 
  left: 30%; 
  top: 70%; 
  background-color: pink; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> 
<div class="parallax_contanier"> 
  <div class="parallax layer1"></div> 
  <div class="parallax layer2"></div> 
  <ul class="layer"> 
    <li class="layer__item"></li> 
    <li class="layer__item"></li> 
    <li class="layer__item"></li> 
  </ul> 
</div>

READ ALSO
navigator.clipboard.writeText() не работает

navigator.clipboard.writeText() не работает

Есть php, он при определённых событиях выводит button

156
ReactJS: Как присвоить переменным результат fetch(список объектов)?

ReactJS: Как присвоить переменным результат fetch(список объектов)?

Новичок в js: Необходимо использовать переменные storeProducts(массив объектов) и detailProduct(конкретный объект) далее в программе, но они не видны за пределами...

70
хеш таблица в js

хеш таблица в js

Вопрос странныйЕсть ли в js встроенная хеш-функция для хеш таблиц? Искал информацию, не нашел

177
Что не так я не понимаю в чем ошибка Uncaught TypeError: Cannot set property &#39;innerHTML&#39; of null [закрыт]

Что не так я не понимаю в чем ошибка Uncaught TypeError: Cannot set property 'innerHTML' of null [закрыт]

Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском

197