Вот решение, которое может сработать для вас:
Каждый элемент (круг) перемещается по случайному пути, используя свойство transform: translate( x, y )
CSS
Каждый элемент получает случайное смещение x, y, на которое он движется по немного другой траектории
Когда каждый элемент достигает границ области просмотра (window.innerWidth = far справа, window.innerHeight = bottom, 0 = top и left) он меняет направление, инвертируя начальные значения смещения offsetX
и offsetY
Анимация в настоящее время реализуется с использованием setInterval
, но лучшим кандидатом может быть requestAnimationFrame
.
(Взгляните на комментарии, которые я разместил вместе с недавно вставленным кодом.)
Codepen
const orderedNumber = document.querySelectorAll('.backgroundBubble');
var colors = [
'#ff5b00', '#b8d500', '#795ced',
'#ab004a', '#21aec0', '#fe9300'
];
const liData = [];
orderedNumber.forEach((li,index)=>{
var random_color = colors[Math.floor(Math.random() * colors.length)];
li.style['background'] = random_color;
var random_dimensions = Math.floor(Math.random() * 20 + 5);
li.style['width'] = random_dimensions + "px";
li.style['height'] = random_dimensions + "px";
var random_left = Math.floor(Math.random() * 99 + 1);
li.style['left'] = random_left + "%";
var random_top = Math.floor(Math.random() * 99 + 1);
li.style['top'] = random_top + "%";
// ADDING MOVEMENT VALUES: In here each element
// gets some additional data that will be used to define its movement.
liData[index] = {
hasFlipped: false, // Has the element hit a viewport boundary? If yes, this property gets flipped: false -> true -> false
targetX: 0, // Current x position. Starts at 0.
targetY: 0, // Current y position. Starts at 0.
offsetX: Math.floor( Math.random() * 10 ), // Random x offset by which the element will move across the x axis
offsetY: Math.floor( Math.random() * 10 ) // Random y offset by which the element will move across the y axis
}
});
setInterval(function(){
orderedNumber.forEach((li,index)=>{
// Next line will give us the top, left, right and bottom position of the element:
const { top, left, right, bottom } = li.getBoundingClientRect();
// Get the offsetX and offsetY so that we can move the element
let { offsetX, offsetY } = liData[index];
if ( liData[index].hasFlipped ){
// Did the element just hit the top or left viewport boundaries?
if ( top <= 0 || left <= 0 ){
// ...if so, flip its movement direction
liData[index].hasFlipped = false;
}
liData[index].targetX -= offsetX;
liData[index].targetY -= offsetY;
} else {
// Did the element just hit the bottom, right viewport boundaries?
// ...if so, flip its movement direction
if ( bottom >= window.innerHeight || right >= window.innerWidth ){
liData[index].hasFlipped = true;
}
liData[index].targetX += offsetX;
liData[index].targetY += offsetY;
}
li.style.transform = `translate( ${liData[index].targetX}px, ${liData[index].targetY}px )`;
});
}, 50 )
@import url('https://fonts.googleapis.com/css?family=Exo:400,700');
*{
margin: 0px;
padding: 0px;
}
.context {
width: 100%;
position: absolute;
top:50vh;
}
.context h1{
text-align: center;
color: #fff;
font-size: 50px;
font-family: 'Exo', sans-serif;
}
.area{
background: #2a2e31;
background: -webkit-linear-gradient(to left, #8f94fb, #4e54c8); // #026e9f #03a9f4
width: 100%;
height:100vh;
}
.circles{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.circles li{
position: absolute;
display: block;
list-style: none;
bottom: -150px;
border-radius: 50%;
}
<div class="context">
<h1>Hello</h1>
</div>
<div class="area">
<ul class="circles">
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
</ul>
</div>
Как можно изменить код движения, чтобы вместо изменения направления движения он отскакивал от стены?
В этом случае мы можем проверить, мяч попадает в одну из границ, и если он попадает в одну из левых / правых сторон, мы переворачиваем знак X (положение -> отрицательное -> положительное -> ...) в противном случае, если он попадает в одну из верхних / нижних сторон сторон мы переворачиваем знак Y.
Вот эскиз, чтобы прояснить это:
const orderedNumber = document.querySelectorAll('.backgroundBubble');
var colors = [
'#ff5b00', '#b8d500', '#795ced',
'#ab004a', '#21aec0', '#fe9300'
];
const liData = [];
orderedNumber.forEach((li,index)=>{
var random_color = colors[Math.floor(Math.random() * colors.length)];
li.style['background'] = random_color;
var random_dimensions = Math.floor(Math.random() * 20 + 5);
li.style['width'] = random_dimensions + "px";
li.style['height'] = random_dimensions + "px";
var random_left = Math.floor(Math.random() * 99 + 1);
li.style['left'] = random_left + "%";
var random_top = Math.floor(Math.random() * 99 + 1);
li.style['top'] = random_top + "%";
// ADDING MOVEMENT VALUES:
liData[index] = {
targetX: 0,
targetY: 0,
offsetX: Math.floor( Math.random() * 10 ),
offsetY: Math.floor( Math.random() * 10 ),
directionX: 1, // Define each ball's direction using a multiplier. Positive means left-to-right. Negative means right-to-left.
directionY: 1 // Same here, but for top-to-bottom and vice versa
}
});
setInterval(function(){
orderedNumber.forEach((li,index)=>{
const { top, left, right, bottom } = li.getBoundingClientRect();
let { offsetX, offsetY } = liData[index];
// If we've just hit the top or bottom boundaries, we'll flip the Y direction:
if ( top <= 0 || bottom >= window.innerHeight ){
liData[index].directionY = -liData[index].directionY;
}
// If we've just hit the left or right boundaries, we'll flip the X direction:
if ( left <= 0 || right >= window.innerWidth){
liData[index].directionX = -liData[index].directionX;
}
// The multiplier, either 1 or -1, defines the balls direction on each axis:
liData[index].targetX += offsetX * liData[index].directionX;
liData[index].targetY += offsetY * liData[index].directionY;
li.style.transform = `translate( ${liData[index].targetX}px, ${liData[index].targetY}px )`;
});
}, 50 )
@import url('https://fonts.googleapis.com/css?family=Exo:400,700');
*{
margin: 0px;
padding: 0px;
}
.context {
width: 100%;
position: absolute;
top:50vh;
}
.context h1{
text-align: center;
color: #fff;
font-size: 50px;
font-family: 'Exo', sans-serif;
}
.area{
background: #2a2e31;
background: -webkit-linear-gradient(to left, #8f94fb, #4e54c8); // #026e9f #03a9f4
width: 100%;
height:100vh;
}
.circles{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.circles li{
position: absolute;
display: block;
list-style: none;
bottom: -150px;
border-radius: 50%;
}
<div class="context">
<h1>Hello</h1>
</div>
<div class="area">
<ul class="circles">
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
<li class="backgroundBubble"></li>
</ul>
</div>
Codepen
Следующие шаги:
Вы можете использовать requestAnimationFrame вместо setInterval()
для повышения производительности.
Поэкспериментируйте с различными случайными схемами для значений смещения x и y, чтобы ввести больше траекторий и элементов, движущихся с разными скоростями