Floating depth cards

Scattered cards drift at their own speeds, so the page feels like a stack of glass sheets.

How it works

Cards are absolutely placed through a tall field. Each one gets a random speed between −0.3 and 0.5; small, blurred cards get slow speeds to read as far away, large sharp ones fast speeds to read as close.

Full file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Floating depth cards</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-font-smoothing: antialiased; }

body { background: #0f2027; color: #fff; overflow-x: hidden; }
.field { position: relative; height: 300vh; }
.field h1 { position: sticky; top: 40vh; text-align: center; margin: 0; font-size: 3rem; z-index: 5; mix-blend-mode: difference; }
.f { position: absolute; border-radius: 14px; will-change: transform; }
</style>
</head>
<body>
<div class="field" id="field"><h1>Depth field</h1></div>
<script>
const field = document.getElementById('field');
const palette = ['#2ec4b6', '#ff9f1c', '#e71d36', '#cbf3f0', '#ffbf69'];
const items = [];
for (let i = 0; i < 28; i++) {
  const d = Math.random();
  const el = document.createElement('div');
  el.className = 'f';
  const size = 40 + d * 160;
  el.style.cssText = 'width:' + size + 'px;height:' + (size * 0.7) + 'px;left:' + (Math.random() * 90) + '%;top:' + (Math.random() * 280) + 'vh;background:' + palette[i % 5] + ';filter:blur(' + ((1 - d) * 4).toFixed(1) + 'px);opacity:' + (0.35 + d * 0.65).toFixed(2) + ';z-index:' + Math.round(d * 10);
  field.appendChild(el);
  items.push({ el, speed: -0.3 + d * 0.8 });
}
function update() {
  items.forEach(o => { o.el.style.transform = 'translate3d(0,' + (-scrollY * o.speed) + 'px,0)'; });
}
addEventListener('scroll', update, { passive: true });
update();
</script>
</body>
</html>

More parallax effects