Háttéranimációk
Élő háló
Élő előnézet – az animáció teljes méretben.
Élő előnézet
HTML · CSS · JS
<div class="we-bg-network">
<canvas class="we-bg-network-canvas"></canvas>
<div class="we-bg-network-content">
<span>WEBELEMENTS</span>
<h2>Élő hálózat</h2>
<p>
Egy folyamatosan változó digitális tér a háttérben.
</p>
</div>
</div>
.we-bg-network {
position: relative;
width: 100%;
min-height: 420px;
overflow: hidden;
background: #080b11;
display: flex;
align-items: center;
justify-content: center;
isolation: isolate;
}
.we-bg-network-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: .72;
}
.we-bg-network-content {
position: relative;
z-index: 2;
max-width: 620px;
padding: 45px;
text-align: center;
color: #f4f1e9;
pointer-events: none;
}
.we-bg-network-content span {
display: block;
margin-bottom: 16px;
color: #7ac98e;
font-family: Inter, system-ui, sans-serif;
font-size: 10px;
font-weight: 700;
letter-spacing: .2em;
}
.we-bg-network-content h2 {
margin: 0 0 14px;
font-family: "Bodoni Moda", Georgia, serif;
font-size: clamp(40px, 7vw, 72px);
font-weight: 500;
line-height: 1;
}
.we-bg-network-content p {
margin: 0;
color: rgba(244, 241, 233, .62);
font-family: Inter, system-ui, sans-serif;
font-size: 14px;
line-height: 1.7;
}
document.querySelectorAll(".we-bg-network").forEach(background => {
const canvas = background.querySelector(
".we-bg-network-canvas"
);
const ctx = canvas.getContext("2d");
let width;
let height;
let animationFrame;
const mouse = {
x: null,
y: null
};
const particles = [];
function resize() {
const rect = background.getBoundingClientRect();
width = canvas.width = rect.width;
height = canvas.height = rect.height;
particles.length = 0;
const count = Math.min(
70,
Math.max(35, Math.floor(width / 14))
);
for (let i = 0; i < count; i++) {
particles.push({
x: Math.random() * width,
y: Math.random() * height,
vx: (Math.random() - .5) * .22,
vy: (Math.random() - .5) * .22,
size: Math.random() * 1.5 + .6
});
}
}
function draw() {
ctx.clearRect(0, 0, width, height);
particles.forEach(particle => {
if (mouse.x !== null) {
const dx = particle.x - mouse.x;
const dy = particle.y - mouse.y;
const distance =
Math.sqrt(dx * dx + dy * dy);
if (distance < 110 && distance > 0) {
const force =
(110 - distance) / 110;
particle.x +=
(dx / distance) * force * .8;
particle.y +=
(dy / distance) * force * .8;
}
}
particle.x += particle.vx;
particle.y += particle.vy;
if (particle.x < -20) particle.x = width + 20;
if (particle.x > width + 20) particle.x = -20;
if (particle.y < -20) particle.y = height + 20;
if (particle.y > height + 20) particle.y = -20;
ctx.beginPath();
ctx.arc(
particle.x,
particle.y,
particle.size,
0,
Math.PI * 2
);
ctx.fillStyle =
"rgba(122, 201, 142, .55)";
ctx.fill();
});
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const dx =
particles[i].x - particles[j].x;
const dy =
particles[i].y - particles[j].y;
const distance =
Math.sqrt(dx * dx + dy * dy);
if (distance < 105) {
const opacity =
(1 - distance / 105) * .24;
ctx.beginPath();
ctx.moveTo(
particles[i].x,
particles[i].y
);
ctx.lineTo(
particles[j].x,
particles[j].y
);
ctx.strokeStyle =
`rgba(122, 201, 142, ${opacity})`;
ctx.lineWidth = .7;
ctx.stroke();
}
}
}
animationFrame =
requestAnimationFrame(draw);
}
background.addEventListener("mousemove", event => {
const rect = background.getBoundingClientRect();
mouse.x =
event.clientX - rect.left;
mouse.y =
event.clientY - rect.top;
});
background.addEventListener("mouseleave", () => {
mouse.x = null;
mouse.y = null;
});
window.addEventListener("resize", resize);
resize();
draw();
});