28 CSS Stacked Card Designs 05 / 28
Swipeable / Click-to-Front Stacked Cards
A Tinder-style flashcard deck optimized for the web: drag the top card (mouse or touch) past a threshold to send it to the back, or simply click it to cycle through.
Best forflashcard learning apps, quick-choice discovery widgets, and interactive portfolios.
The code
<div class="scd-flash">
<div class="scd-flash__stage" data-scd-flash="stage">
<div class="scd-flash__counter"><span data-scd-flash="pos">01 / 04</span><span class="scd-flash__prog"><i data-scd-flash="bar" style="width:0%"></i></span><span>DECK</span></div>
<div class="scd-flash__deck" data-scd-flash="deck">
<div class="scd-flash__card scd-flash__card--g4"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Biology</span><div class="scd-flash__term">Mitosis</div><div><p class="scd-flash__def">Cell division producing two genetically identical daughter cells.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
<div class="scd-flash__card scd-flash__card--g3"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Physics</span><div class="scd-flash__term">Photon</div><div><p class="scd-flash__def">A discrete quantum, or packet, of electromagnetic energy — light.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
<div class="scd-flash__card scd-flash__card--g2"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Thermo</span><div class="scd-flash__term">Entropy</div><div><p class="scd-flash__def">A measure of disorder; the tendency of systems toward equilibrium.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
<div class="scd-flash__card scd-flash__card--g1"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Biology</span><div class="scd-flash__term">Osmosis</div><div><p class="scd-flash__def">Water moving across a semipermeable membrane toward higher solute.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
</div>
<div class="scd-flash__hint">swipe <b>right = know</b> · <i>left = review</i> · click to skip</div>
</div>
</div> <div class="scd-flash">
<div class="scd-flash__stage" data-scd-flash="stage">
<div class="scd-flash__counter"><span data-scd-flash="pos">01 / 04</span><span class="scd-flash__prog"><i data-scd-flash="bar" style="width:0%"></i></span><span>DECK</span></div>
<div class="scd-flash__deck" data-scd-flash="deck">
<div class="scd-flash__card scd-flash__card--g4"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Biology</span><div class="scd-flash__term">Mitosis</div><div><p class="scd-flash__def">Cell division producing two genetically identical daughter cells.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
<div class="scd-flash__card scd-flash__card--g3"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Physics</span><div class="scd-flash__term">Photon</div><div><p class="scd-flash__def">A discrete quantum, or packet, of electromagnetic energy — light.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
<div class="scd-flash__card scd-flash__card--g2"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Thermo</span><div class="scd-flash__term">Entropy</div><div><p class="scd-flash__def">A measure of disorder; the tendency of systems toward equilibrium.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
<div class="scd-flash__card scd-flash__card--g1"><div class="scd-flash__grad"></div><div class="scd-flash__glow"></div><div class="scd-flash__sheen"></div>
<span class="scd-flash__verdict scd-flash__verdict--know">KNOW ✓</span><span class="scd-flash__verdict scd-flash__verdict--again">AGAIN ↻</span>
<div class="scd-flash__face"><span class="scd-flash__tag">Biology</span><div class="scd-flash__term">Osmosis</div><div><p class="scd-flash__def">Water moving across a semipermeable membrane toward higher solute.</p><br><span class="scd-flash__fliphint">drag · or click for next</span></div></div></div>
</div>
<div class="scd-flash__hint">swipe <b>right = know</b> · <i>left = review</i> · click to skip</div>
</div>
</div>@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@300;400;500;600;700&family=Geist+Mono:wght@400&display=swap');
.scd-flash, .scd-flash *, .scd-flash *::before, .scd-flash *::after { box-sizing: border-box; margin: 0; padding: 0; }
.scd-flash {
position: relative;
min-height: 460px;
display: grid;
place-items: center;
background: #05060a;
font-family: 'Geist', sans-serif;
}
.scd-flash::before {
content: '';
position: absolute; inset: -30%;
background:
radial-gradient(40% 40% at 22% 28%, rgba(56,189,248,.30), transparent 70%),
radial-gradient(45% 45% at 78% 25%, rgba(168,85,247,.28), transparent 70%),
radial-gradient(50% 50% at 50% 82%, rgba(244,114,182,.24), transparent 70%);
filter: blur(26px);
animation: scd-flash-drift 19s ease-in-out infinite alternate;
pointer-events: none;
}
@keyframes scd-flash-drift {
0% { transform: translate(-3%,-2%) scale(1); }
100% { transform: translate(4%,3%) scale(1.1); }
}
.scd-flash::after {
content: '';
position: absolute; inset: 0;
background: repeating-linear-gradient(0deg, rgba(255,255,255,.02) 0 1px, transparent 1px 3px);
mix-blend-mode: overlay;
pointer-events: none;
}
.scd-flash__stage { position: relative; width: 280px; height: 380px; perspective: 1300px; z-index: 1; }
.scd-flash__counter {
position: absolute; top: -46px; left: 0; right: 0;
display: flex; align-items: center; justify-content: space-between;
font-family: 'Geist Mono', monospace;
font-size: .72rem; letter-spacing: .15em;
color: rgba(255,255,255,.55);
}
.scd-flash__prog { flex: 1; height: 3px; margin: 0 12px; background: rgba(255,255,255,.15); border-radius: 3px; overflow: hidden; }
.scd-flash__prog i { display: block; height: 100%; background: #fff; border-radius: 3px; transition: width .4s; box-shadow: 0 0 10px rgba(255,255,255,.6); }
.scd-flash__deck { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; }
.scd-flash__card {
position: absolute; inset: 0;
border-radius: 26px;
transform-style: preserve-3d;
cursor: grab;
user-select: none;
overflow: hidden;
box-shadow: 0 30px 60px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,.09) inset;
transition: transform .5s cubic-bezier(.16,1,.3,1), opacity .5s, box-shadow .5s;
}
.scd-flash__card.scd-flash__card--drag { transition: none; cursor: grabbing; }
.scd-flash__grad { position: absolute; inset: 0; background-size: 200% 200%; animation: scd-flash-flow 8s ease infinite; }
@keyframes scd-flash-flow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.scd-flash__glow {
position: absolute; inset: 0;
background: radial-gradient(260px circle at var(--mx,50%) var(--my,40%), rgba(255,255,255,.4), transparent 60%);
mix-blend-mode: soft-light;
opacity: 0;
transition: opacity .4s;
}
.scd-flash__card:hover .scd-flash__glow { opacity: 1; }
.scd-flash__sheen {
position: absolute; top: -50%; left: -30%;
width: 55%; height: 200%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,.45), transparent);
transform: rotate(18deg) translateX(-260px);
transition: transform .9s cubic-bezier(.16,1,.3,1);
}
.scd-flash__verdict {
position: absolute; top: 24px;
padding: 8px 16px;
border-radius: 12px;
font-family: 'Geist Mono', monospace;
font-size: .85rem; font-weight: 700;
letter-spacing: .1em;
border: 2px solid;
opacity: 0;
transition: opacity .15s;
backdrop-filter: blur(4px);
}
.scd-flash__verdict--know { right: 22px; color: #86efac; border-color: #86efac; transform: rotate(10deg); }
.scd-flash__verdict--again { left: 22px; color: #fca5a5; border-color: #fca5a5; transform: rotate(-10deg); }
.scd-flash__face {
position: absolute; inset: 0;
padding: 30px;
display: flex; flex-direction: column; justify-content: space-between;
transform: translateZ(40px);
color: #fff;
}
.scd-flash__tag {
font-family: 'Geist Mono', monospace;
font-size: .62rem; letter-spacing: .22em; text-transform: uppercase;
padding: 6px 12px; border-radius: 999px;
background: rgba(255,255,255,.16);
border: 1px solid rgba(255,255,255,.24);
align-self: flex-start;
backdrop-filter: blur(6px);
}
.scd-flash__term {
font-family: 'Instrument Serif', serif;
font-size: 2.7rem; line-height: 1; letter-spacing: -.01em;
text-shadow: 0 3px 18px rgba(0,0,0,.3);
}
.scd-flash__def { font-size: .9rem; opacity: .9; line-height: 1.5; font-weight: 300; }
.scd-flash__fliphint { font-family: 'Geist Mono', monospace; font-size: .62rem; letter-spacing: .18em; opacity: .6; }
.scd-flash__card--g1 .scd-flash__grad { background: linear-gradient(135deg,#831843,#db2777 45%,#fb7185); }
.scd-flash__card--g2 .scd-flash__grad { background: linear-gradient(135deg,#0c4a6e,#0284c7 45%,#38bdf8); }
.scd-flash__card--g3 .scd-flash__grad { background: linear-gradient(135deg,#064e3b,#059669 50%,#34d399); }
.scd-flash__card--g4 .scd-flash__grad { background: linear-gradient(135deg,#581c87,#7c3aed 45%,#a78bfa); }
.scd-flash__hint {
position: absolute; bottom: -46px; left: 0; right: 0;
text-align: center;
font-family: 'Geist Mono', monospace;
color: rgba(255,255,255,.5);
font-size: .7rem;
letter-spacing: .12em;
}
.scd-flash__hint b { color: #86efac; }
.scd-flash__hint i { color: #fca5a5; font-style: normal; }
@media (prefers-reduced-motion: reduce) {
.scd-flash::before,
.scd-flash__grad,
.scd-flash__sheen,
.scd-flash__card,
.scd-flash__prog i { animation: none !important; transition: none !important; }
} @import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@300;400;500;600;700&family=Geist+Mono:wght@400&display=swap');
.scd-flash, .scd-flash *, .scd-flash *::before, .scd-flash *::after { box-sizing: border-box; margin: 0; padding: 0; }
.scd-flash {
position: relative;
min-height: 460px;
display: grid;
place-items: center;
background: #05060a;
font-family: 'Geist', sans-serif;
}
.scd-flash::before {
content: '';
position: absolute; inset: -30%;
background:
radial-gradient(40% 40% at 22% 28%, rgba(56,189,248,.30), transparent 70%),
radial-gradient(45% 45% at 78% 25%, rgba(168,85,247,.28), transparent 70%),
radial-gradient(50% 50% at 50% 82%, rgba(244,114,182,.24), transparent 70%);
filter: blur(26px);
animation: scd-flash-drift 19s ease-in-out infinite alternate;
pointer-events: none;
}
@keyframes scd-flash-drift {
0% { transform: translate(-3%,-2%) scale(1); }
100% { transform: translate(4%,3%) scale(1.1); }
}
.scd-flash::after {
content: '';
position: absolute; inset: 0;
background: repeating-linear-gradient(0deg, rgba(255,255,255,.02) 0 1px, transparent 1px 3px);
mix-blend-mode: overlay;
pointer-events: none;
}
.scd-flash__stage { position: relative; width: 280px; height: 380px; perspective: 1300px; z-index: 1; }
.scd-flash__counter {
position: absolute; top: -46px; left: 0; right: 0;
display: flex; align-items: center; justify-content: space-between;
font-family: 'Geist Mono', monospace;
font-size: .72rem; letter-spacing: .15em;
color: rgba(255,255,255,.55);
}
.scd-flash__prog { flex: 1; height: 3px; margin: 0 12px; background: rgba(255,255,255,.15); border-radius: 3px; overflow: hidden; }
.scd-flash__prog i { display: block; height: 100%; background: #fff; border-radius: 3px; transition: width .4s; box-shadow: 0 0 10px rgba(255,255,255,.6); }
.scd-flash__deck { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; }
.scd-flash__card {
position: absolute; inset: 0;
border-radius: 26px;
transform-style: preserve-3d;
cursor: grab;
user-select: none;
overflow: hidden;
box-shadow: 0 30px 60px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,.09) inset;
transition: transform .5s cubic-bezier(.16,1,.3,1), opacity .5s, box-shadow .5s;
}
.scd-flash__card.scd-flash__card--drag { transition: none; cursor: grabbing; }
.scd-flash__grad { position: absolute; inset: 0; background-size: 200% 200%; animation: scd-flash-flow 8s ease infinite; }
@keyframes scd-flash-flow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.scd-flash__glow {
position: absolute; inset: 0;
background: radial-gradient(260px circle at var(--mx,50%) var(--my,40%), rgba(255,255,255,.4), transparent 60%);
mix-blend-mode: soft-light;
opacity: 0;
transition: opacity .4s;
}
.scd-flash__card:hover .scd-flash__glow { opacity: 1; }
.scd-flash__sheen {
position: absolute; top: -50%; left: -30%;
width: 55%; height: 200%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,.45), transparent);
transform: rotate(18deg) translateX(-260px);
transition: transform .9s cubic-bezier(.16,1,.3,1);
}
.scd-flash__verdict {
position: absolute; top: 24px;
padding: 8px 16px;
border-radius: 12px;
font-family: 'Geist Mono', monospace;
font-size: .85rem; font-weight: 700;
letter-spacing: .1em;
border: 2px solid;
opacity: 0;
transition: opacity .15s;
backdrop-filter: blur(4px);
}
.scd-flash__verdict--know { right: 22px; color: #86efac; border-color: #86efac; transform: rotate(10deg); }
.scd-flash__verdict--again { left: 22px; color: #fca5a5; border-color: #fca5a5; transform: rotate(-10deg); }
.scd-flash__face {
position: absolute; inset: 0;
padding: 30px;
display: flex; flex-direction: column; justify-content: space-between;
transform: translateZ(40px);
color: #fff;
}
.scd-flash__tag {
font-family: 'Geist Mono', monospace;
font-size: .62rem; letter-spacing: .22em; text-transform: uppercase;
padding: 6px 12px; border-radius: 999px;
background: rgba(255,255,255,.16);
border: 1px solid rgba(255,255,255,.24);
align-self: flex-start;
backdrop-filter: blur(6px);
}
.scd-flash__term {
font-family: 'Instrument Serif', serif;
font-size: 2.7rem; line-height: 1; letter-spacing: -.01em;
text-shadow: 0 3px 18px rgba(0,0,0,.3);
}
.scd-flash__def { font-size: .9rem; opacity: .9; line-height: 1.5; font-weight: 300; }
.scd-flash__fliphint { font-family: 'Geist Mono', monospace; font-size: .62rem; letter-spacing: .18em; opacity: .6; }
.scd-flash__card--g1 .scd-flash__grad { background: linear-gradient(135deg,#831843,#db2777 45%,#fb7185); }
.scd-flash__card--g2 .scd-flash__grad { background: linear-gradient(135deg,#0c4a6e,#0284c7 45%,#38bdf8); }
.scd-flash__card--g3 .scd-flash__grad { background: linear-gradient(135deg,#064e3b,#059669 50%,#34d399); }
.scd-flash__card--g4 .scd-flash__grad { background: linear-gradient(135deg,#581c87,#7c3aed 45%,#a78bfa); }
.scd-flash__hint {
position: absolute; bottom: -46px; left: 0; right: 0;
text-align: center;
font-family: 'Geist Mono', monospace;
color: rgba(255,255,255,.5);
font-size: .7rem;
letter-spacing: .12em;
}
.scd-flash__hint b { color: #86efac; }
.scd-flash__hint i { color: #fca5a5; font-style: normal; }
@media (prefers-reduced-motion: reduce) {
.scd-flash::before,
.scd-flash__grad,
.scd-flash__sheen,
.scd-flash__card,
.scd-flash__prog i { animation: none !important; transition: none !important; }
}(() => {
const root = document.querySelector('.scd-flash');
if (!root) return;
const stage = root.querySelector('[data-scd-flash="stage"]');
const deck = root.querySelector('[data-scd-flash="deck"]');
const posEl = root.querySelector('[data-scd-flash="pos"]');
const barEl = root.querySelector('[data-scd-flash="bar"]');
if (!stage || !deck) return;
const total = deck.querySelectorAll('.scd-flash__card').length;
let done = 0;
function meter() {
const current = Math.min(done + 1, total);
if (posEl) posEl.textContent = String(current).padStart(2, '0') + ' / ' + String(total).padStart(2, '0');
if (barEl) barEl.style.width = (done / total * 100) + '%';
}
function layout(instant) {
const cards = [...deck.querySelectorAll('.scd-flash__card')];
cards.forEach((c, i) => {
const d = cards.length - 1 - i;
const tf = `translateY(${d * -14}px) translateZ(${-d * 30}px) scale(${1 - d * .05})`;
if (instant) {
const t = c.style.transition;
c.style.transition = 'none';
c.style.transform = tf;
void c.offsetWidth;
c.style.transition = t;
} else {
c.style.transform = tf;
}
c.style.zIndex = i + 1;
c.style.opacity = d > 3 ? 0 : 1;
c.style.filter = `brightness(${1 - d * .12})`;
});
}
function sendBack(card, dir) {
done++; meter();
card.style.transform = `translateX(${dir * 480}px) rotate(${dir * 22}deg)`;
card.style.opacity = '0';
setTimeout(() => {
card.style.transition = 'none';
deck.insertBefore(card, deck.firstElementChild);
card.style.opacity = '';
card.style.filter = '';
const k = card.querySelector('.scd-flash__verdict--know');
const a = card.querySelector('.scd-flash__verdict--again');
if (k) k.style.opacity = 0;
if (a) a.style.opacity = 0;
layout(true);
void card.offsetWidth;
card.style.transition = '';
if (done >= total) done = 0;
meter(); bind();
}, 420);
}
let activeTop = null;
let sx = 0, dx = 0, drag = false, moved = false;
let know = null, again = null;
function onDown(e) {
drag = true; moved = false;
sx = (e.touches ? e.touches[0].clientX : e.clientX);
if (activeTop) activeTop.classList.add('scd-flash__card--drag');
}
function onMove(e) {
if (!drag || !activeTop) return;
dx = (e.touches ? e.touches[0].clientX : e.clientX) - sx;
if (Math.abs(dx) > 5) moved = true;
activeTop.style.transform = `translateX(${dx}px) rotate(${dx * .05}deg)`;
if (know) know.style.opacity = Math.max(0, Math.min(1, dx / 90));
if (again) again.style.opacity = Math.max(0, Math.min(1, -dx / 90));
}
function onUp() {
if (!drag || !activeTop) return;
drag = false;
activeTop.classList.remove('scd-flash__card--drag');
if (!moved) { sendBack(activeTop, -1); return; }
if (Math.abs(dx) > 100) {
sendBack(activeTop, dx > 0 ? 1 : -1);
} else {
if (know) know.style.opacity = 0;
if (again) again.style.opacity = 0;
layout();
}
dx = 0;
}
function bind() {
const cards = [...deck.querySelectorAll('.scd-flash__card')];
const top = cards[cards.length - 1];
if (!top) return;
activeTop = top;
know = top.querySelector('.scd-flash__verdict--know');
again = top.querySelector('.scd-flash__verdict--again');
top.onmousedown = onDown;
top.ontouchstart = onDown;
}
root.addEventListener('mousemove', onMove);
root.addEventListener('touchmove', onMove, { passive: true });
root.addEventListener('mouseup', onUp);
root.addEventListener('touchend', onUp);
root.addEventListener('mouseleave', onUp);
stage.addEventListener('mousemove', (e) => {
stage.querySelectorAll('.scd-flash__card').forEach((c) => {
const r = c.getBoundingClientRect();
c.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%');
c.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%');
});
});
meter(); layout(); bind();
})(); (() => {
const root = document.querySelector('.scd-flash');
if (!root) return;
const stage = root.querySelector('[data-scd-flash="stage"]');
const deck = root.querySelector('[data-scd-flash="deck"]');
const posEl = root.querySelector('[data-scd-flash="pos"]');
const barEl = root.querySelector('[data-scd-flash="bar"]');
if (!stage || !deck) return;
const total = deck.querySelectorAll('.scd-flash__card').length;
let done = 0;
function meter() {
const current = Math.min(done + 1, total);
if (posEl) posEl.textContent = String(current).padStart(2, '0') + ' / ' + String(total).padStart(2, '0');
if (barEl) barEl.style.width = (done / total * 100) + '%';
}
function layout(instant) {
const cards = [...deck.querySelectorAll('.scd-flash__card')];
cards.forEach((c, i) => {
const d = cards.length - 1 - i;
const tf = `translateY(${d * -14}px) translateZ(${-d * 30}px) scale(${1 - d * .05})`;
if (instant) {
const t = c.style.transition;
c.style.transition = 'none';
c.style.transform = tf;
void c.offsetWidth;
c.style.transition = t;
} else {
c.style.transform = tf;
}
c.style.zIndex = i + 1;
c.style.opacity = d > 3 ? 0 : 1;
c.style.filter = `brightness(${1 - d * .12})`;
});
}
function sendBack(card, dir) {
done++; meter();
card.style.transform = `translateX(${dir * 480}px) rotate(${dir * 22}deg)`;
card.style.opacity = '0';
setTimeout(() => {
card.style.transition = 'none';
deck.insertBefore(card, deck.firstElementChild);
card.style.opacity = '';
card.style.filter = '';
const k = card.querySelector('.scd-flash__verdict--know');
const a = card.querySelector('.scd-flash__verdict--again');
if (k) k.style.opacity = 0;
if (a) a.style.opacity = 0;
layout(true);
void card.offsetWidth;
card.style.transition = '';
if (done >= total) done = 0;
meter(); bind();
}, 420);
}
let activeTop = null;
let sx = 0, dx = 0, drag = false, moved = false;
let know = null, again = null;
function onDown(e) {
drag = true; moved = false;
sx = (e.touches ? e.touches[0].clientX : e.clientX);
if (activeTop) activeTop.classList.add('scd-flash__card--drag');
}
function onMove(e) {
if (!drag || !activeTop) return;
dx = (e.touches ? e.touches[0].clientX : e.clientX) - sx;
if (Math.abs(dx) > 5) moved = true;
activeTop.style.transform = `translateX(${dx}px) rotate(${dx * .05}deg)`;
if (know) know.style.opacity = Math.max(0, Math.min(1, dx / 90));
if (again) again.style.opacity = Math.max(0, Math.min(1, -dx / 90));
}
function onUp() {
if (!drag || !activeTop) return;
drag = false;
activeTop.classList.remove('scd-flash__card--drag');
if (!moved) { sendBack(activeTop, -1); return; }
if (Math.abs(dx) > 100) {
sendBack(activeTop, dx > 0 ? 1 : -1);
} else {
if (know) know.style.opacity = 0;
if (again) again.style.opacity = 0;
layout();
}
dx = 0;
}
function bind() {
const cards = [...deck.querySelectorAll('.scd-flash__card')];
const top = cards[cards.length - 1];
if (!top) return;
activeTop = top;
know = top.querySelector('.scd-flash__verdict--know');
again = top.querySelector('.scd-flash__verdict--again');
top.onmousedown = onDown;
top.ontouchstart = onDown;
}
root.addEventListener('mousemove', onMove);
root.addEventListener('touchmove', onMove, { passive: true });
root.addEventListener('mouseup', onUp);
root.addEventListener('touchend', onUp);
root.addEventListener('mouseleave', onUp);
stage.addEventListener('mousemove', (e) => {
stage.querySelectorAll('.scd-flash__card').forEach((c) => {
const r = c.getBoundingClientRect();
c.style.setProperty('--mx', ((e.clientX - r.left) / r.width * 100) + '%');
c.style.setProperty('--my', ((e.clientY - r.top) / r.height * 100) + '%');
});
});
meter(); layout(); bind();
})();More from 28 CSS Stacked Card Designs
Shuffle RevealSwipe StackAccordion Card3D Flip StackTilt on HoverScratch CardsCSS Stacked Cards Hover RevealPure CSS Stacked Card Testimonial Slider3D Overlapping Stacked Cards (Isometric View)Minimalist Bento Grid Stacked CardsClassic DeckFan Spread
View the full collection →