Stacking cards

Cards pin one on top of another and the ones underneath shrink back into a neat pile.

How it works

Every card is position: sticky with a slightly larger top offset than the one before, which creates the pile with CSS alone. A small script scales each card down a little as the next card slides over it.

Full file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Stacking 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: #1c1b29; color: #1c1b29; }
.hd { height: 50vh; display: grid; place-content: center; text-align: center; color: #fff; }
.hd h1 { font-size: 3rem; margin: 0; }
.stack { padding: 0 8vw; }
.card {
  position: sticky; top: calc(10vh + var(--i) * 18px);
  height: 60vh; margin-bottom: 12vh; border-radius: 22px; background: var(--c);
  padding: 32px; transform-origin: 50% 0; will-change: transform;
  box-shadow: 0 -12px 30px rgba(0,0,0,.25);
}
.card h2 { font: 800 clamp(2.5rem, 8vw, 5rem)/1 system-ui, sans-serif; margin: 0 0 .3em; }
.card p { font-size: 1.3rem; margin: 0; }
.ft { height: 60vh; display: grid; place-content: center; color: #fff; opacity: .7; }
</style>
</head>
<body>
<header class="hd"><h1>Stacking cards</h1><p>Keep scrolling.</p></header>
<main class="stack" id="stack">
  <article class="card" style="--c:#ff8a5b"><h2>Plan</h2><p>Sketch the idea on paper first.</p></article>
  <article class="card" style="--c:#ffd166"><h2>Build</h2><p>Make the smallest thing that works.</p></article>
  <article class="card" style="--c:#06d6a0"><h2>Test</h2><p>Put it in front of real people.</p></article>
  <article class="card" style="--c:#118ab2"><h2>Ship</h2><p>Release it and keep listening.</p></article>
  <article class="card" style="--c:#8d6cff"><h2>Repeat</h2><p>Every version teaches the next.</p></article>
</main>
<footer class="ft">End of the stack.</footer>
<script>
const cards = [...document.querySelectorAll('.card')];
cards.forEach((c, i) => c.style.setProperty('--i', i));
function update() {
  cards.forEach((c, i) => {
    const next = cards[i + 1];
    if (!next) return;
    const r = c.getBoundingClientRect();
    const n = next.getBoundingClientRect();
    const overlap = Math.min(1, Math.max(0, 1 - (n.top - r.top) / r.height));
    c.style.transform = 'scale(' + (1 - overlap * 0.08).toFixed(4) + ')';
    c.style.filter = 'brightness(' + (1 - overlap * 0.35).toFixed(3) + ')';
  });
}
addEventListener('scroll', update, { passive: true });
update();
</script>
</body>
</html>

More sticky effects