aeworks.tech/lab/tarjetas-apiladas
← AE Lab

Tarjetas que se apilan al hacer scroll

14 oct 2026· nivel avanzadoscroll-driven animationsposition: stickyview-timeline

Página de servicios de una clínica dental donde cada tarjeta se queda pegada arriba y la siguiente sube y se coloca encima, mientras las de debajo se encogen, se oscurecen y se inclinan como una baraja. Todo lo mueve el propio scroll, sin librerías.

// CÓMO ESTÁ HECHO

  1. Cada tarjeta es position: sticky con un top que crece 14 px por índice, así las de debajo asoman por arriba como una baraja.
  2. Antes de cada tarjeta hay una marca invisible con view-timeline-name, y timeline-scope en el contenedor deja que la tarjeta anterior lea la línea de tiempo de la siguiente.
  3. La tarjeta de debajo se anima con animation-timeline y animation-range: cover 0% → cover (100% − top): se encoge desde arriba, gira ±1,6° y un velo ::after sube su opacidad.
  4. Si el navegador no soporta animation-timeline, un respaldo con scroll + requestAnimationFrame hace la misma cuenta (0 → 1) y escribe el transform a mano; la barra de lectura usa scroll(root).
  5. El modo demostración baja con scrollTo frame a frame, vuelve arriba con una curva suave y se para al tocar, mover la rueda o pulsar una tecla.

// EL CÓDIGO

<header class="cabecera">
  <a class="marca-logo" href="#inicio" aria-label="Brisa, clínica dental de ejemplo: inicio" style="color:inherit;text-decoration:none">
    <svg viewBox="0 0 32 32" aria-hidden="true"><path d="M10 5c-4 0-6 3-6 7 0 3 1 5 2 8 1 4 1 9 4 9 2 0 2-6 4-6h4c2 0 2 6 4 6 3 0 3-5 4-9 1-3 2-5 2-8 0-4-2-7-6-7-2 0-4 1-6 1s-4-1-6-1z" fill="none" stroke="#00FF7F" stroke-width="2.2" stroke-linejoin="round"/></svg>
    Brisa <small>· clínica dental</small>
  </a>
  <nav aria-label="Servicios">
    <ol class="indice" id="indice"></ol>
  </nav>
  <div class="progreso" id="progreso" role="progressbar" aria-label="Progreso de lectura" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"></div>
</header>

<main id="inicio">
  <section class="portada">
    <span class="etiqueta mono">Clínica de ejemplo · 5 tratamientos</span>
    <h1>Sonríe <em>sin prisas.</em></h1>
    <p>Desliza: cada tratamiento se queda arriba y el siguiente se coloca encima, como una baraja.</p>
  </section>

  <!-- La pila. Cada tarjeta lleva: --i (posición), --lado (+1/-1 para inclinar) y --linea (marca de la siguiente) -->
  <section class="pila" id="pila" aria-label="Tratamientos">

    <div class="marca" data-i="0"></div>
    <article class="tarjeta" style="--i:0; --lado:-1; --linea:--m1" aria-labelledby="t0">
      <div class="lamina">
        <div class="dibujo" aria-hidden="true">
          <svg viewBox="0 0 120 120"><path d="M38 24c-11 0-18 8-18 20 0 9 3 14 5 22 2 11 3 30 11 30 6 0 6-17 12-17h4c6 0 6 17 12 17 8 0 9-19 11-30 2-8 5-13 5-22 0-12-7-20-18-20-6 0-9 3-13 3s-7-3-11-3z"/><circle cx="84" cy="80" r="14"/><path d="M94 90l12 12"/></svg>
        </div>
        <div class="texto">
          <span class="num mono">01 / 05 · PREVENCIÓN</span>
          <h2 id="t0">Revisión e higiene</h2>
          <p>Limpieza profunda, revisión completa y un plan claro. Sin sustos ni letra pequeña.</p>
          <ul><li>Diagnóstico digital en 20 minutos</li><li>Limpieza con ultrasonidos</li><li>Informe en tu móvil</li></ul>
          <div class="pie"><span class="precio">desde<b>45 €</b></span><button class="btn" data-servicio="Revisión e higiene">Reservar</button></div>
        </div>
      </div>
    </article>

    <div class="marca" data-i="1"></div>
    <article class="tarjeta" style="--i:1; --lado:1; --linea:--m2" aria-labelledby="t1">
      <div class="lamina">
        <div class="dibujo" aria-hidden="true">
          <svg viewBox="0 0 120 120"><path d="M18 70c0-26 19-44 42-44s42 18 42 44"/><path d="M28 70c0-20 14-34 32-34s32 14 32 34" stroke-dasharray="4 7"/><rect x="22" y="70" width="12" height="16" rx="5"/><rect x="38" y="72" width="12" height="16" rx="5"/><rect x="54" y="73" width="12" height="16" rx="5"/><rect x="70" y="72" width="12" height="16" rx="5"/><rect x="86" y="70" width="12" height="16" rx="5"/></svg>
        </div>
        <div class="texto">
          <span class="num mono">02 / 05 · ORTODONCIA</span>
          <h2 id="t1">Alineadores invisibles</h2>
          <p>Ves el resultado final en 3D antes de empezar. Férulas que nadie nota.</p>
          <ul><li>Simulación 3D en la primera cita</li><li>Revisiones cada 8 semanas</li><li>Retenedor incluido</li></ul>
          <div class="pie"><span class="precio">desde<b>95 €/mes</b></span><button class="btn" data-servicio="Alineadores invisibles">Reservar</button></div>
        </div>
      </div>
    </article>

    <div class="marca" data-i="2"></div>
    <article class="tarjeta inversa" style="--i:2; --lado:-1; --linea:--m3" aria-labelledby="t2">
      <div class="lamina">
        <div class="dibujo" aria-hidden="true">
          <svg viewBox="0 0 120 120"><path d="M40 14c-8 0-14 6-14 15 0 8 4 13 6 17h56c2-4 6-9 6-17 0-9-6-15-14-15-6 0-9 3-20 3s-14-3-20-3z"/><path d="M48 46v8h24v-8"/><path d="M50 54l-2 40 12 12 12-12-2-40"/><path d="M47 64h26M47 74h26M48 84h24"/></svg>
        </div>
        <div class="texto">
          <span class="num mono">03 / 05 · IMPLANTES</span>
          <h2 id="t2">Dientes fijos en un día</h2>
          <p>Cirugía guiada por ordenador: menos tiempo en el sillón y menos molestias.</p>
          <ul><li>Escáner 3D sin moldes</li><li>Diente provisional el mismo día</li><li>Garantía de 10 años</li></ul>
          <div class="pie"><span class="precio">desde<b>690 €</b></span><button class="btn" data-servicio="Implantes">Reservar</button></div>
        </div>
      </div>
    </article>

    <div class="marca" data-i="3"></div>
    <article class="tarjeta" style="--i:3; --lado:1; --linea:--m4" aria-labelledby="t3">
      <div class="lamina">
        <div class="dibujo" aria-hidden="true">
          <svg viewBox="0 0 120 120"><path d="M34 34c-10 0-16 7-16 18 0 8 3 12 5 19 2 10 3 27 10 27 5 0 5-15 10-15h4c5 0 5 15 10 15 7 0 8-17 10-27 2-7 5-11 5-19 0-11-6-18-16-18-5 0-8 3-11 3s-6-3-11-3z"/><path d="M92 14v20M82 24h20M100 46v12M94 52h12M84 64v8M80 68h8"/></svg>
        </div>
        <div class="texto">
          <span class="num mono">04 / 05 · ESTÉTICA</span>
          <h2 id="t3">Blanqueamiento LED</h2>
          <p>Hasta seis tonos más claro en una sesión, con gel que cuida el esmalte.</p>
          <ul><li>Sesión de 60 minutos</li><li>Sin sensibilidad posterior</li><li>Kit de mantenimiento en casa</li></ul>
          <div class="pie"><span class="precio">desde<b>220 €</b></span><button class="btn" data-servicio="Blanqueamiento">Reservar</button></div>
        </div>
      </div>
    </article>

    <div class="marca" data-i="4"></div>
    <article class="tarjeta" style="--i:4; --lado:-1" aria-labelledby="t4">
      <div class="lamina">
        <div class="dibujo" aria-hidden="true">
          <svg viewBox="0 0 120 120"><circle cx="56" cy="62" r="38"/><path d="M56 38v24l16 10"/><path d="M96 14v20M86 24h20"/></svg>
        </div>
        <div class="texto">
          <span class="num mono">05 / 05 · URGENCIAS</span>
          <h2 id="t4">Urgencias 24 h</h2>
          <p>Dolor, golpe o una pieza rota: te atendemos hoy, también fines de semana.</p>
          <ul><li>Respuesta en menos de 15 minutos</li><li>Hueco reservado cada día</li><li>Primera valoración sin coste</li></ul>
          <div class="pie"><span class="precio">valoración<b>0 €</b></span><button class="btn" data-servicio="Urgencias">Reservar</button></div>
        </div>
      </div>
    </article>
  </section>

  <section class="cierre">
    <h2>Tu primera revisión, <em>sin coste.</em></h2>
    <p>Datos de ejemplo para la demostración. Ningún paciente real, ninguna clínica real.</p>
    <button class="btn" data-servicio="Primera revisión">Pedir cita</button>
  </section>
</main>

<div class="aviso" id="aviso" role="status" aria-live="polite"></div>
<div class="chapa-demo" id="chapa">▶ DEMO · toca para tomar el control</div>