The top card of a stack slides out and tucks in behind while the rest move up a place and brighten, on repeat. One keyframe set plays on every card, a third of a cycle apart through negative delays.
Also known as: card shuffle animation css, stacked cards animation, deck of cards loop css.
<div class="kfa-card-stack-shuffle"><span style="--i: 0">1</span><span style="--i: 1">2</span><span style="--i: 2">3</span></div>
.kfa-card-stack-shuffle {
--c: var(--kfa-color, #3b82f6);
font-size: var(--kfa-size, 16px);
position: relative;
width: 4.4em;
height: 5.4em;
margin-top: 1em;
}
.kfa-card-stack-shuffle > span {
position: absolute;
inset: 0;
display: grid;
place-items: center;
border-radius: 0.8em;
background: linear-gradient(160deg, color-mix(in srgb, var(--c) 78%, #fff), var(--c));
box-shadow: 0 0.5em 1em -0.5em color-mix(in srgb, var(--c) 70%, transparent), inset 0 0 0 1px color-mix(in srgb, var(--c) 40%, transparent);
color: #fff;
font: 700 1.6em/1 system-ui, sans-serif;
animation:
kfa-card-stack-shuffle-deal 4.5s cubic-bezier(0.65, 0, 0.35, 1) infinite,
kfa-card-stack-shuffle-layer 4.5s linear infinite;
animation-delay: calc(var(--i) * -3s);
}
/* front, out to the side, back of the stack, middle, front again */
@keyframes kfa-card-stack-shuffle-deal {
0%, 20% { transform: none; filter: brightness(1); }
27% { transform: translate(3.4em, -0.4em) rotate(10deg); filter: brightness(1); }
33.33%, 53.33% { transform: translateY(-1em) scale(0.84); filter: brightness(0.78); }
66.67%, 86.67% { transform: translateY(-0.5em) scale(0.92); filter: brightness(0.89); }
100% { transform: none; filter: brightness(1); }
}
/* the stacking order flips while the card is clear of the others */
@keyframes kfa-card-stack-shuffle-layer {
0%, 27% { z-index: 3; }
27.5%, 61.5% { z-index: 1; }
62%, 93.5% { z-index: 2; }
94%, 100% { z-index: 3; }
}
@media (prefers-reduced-motion: reduce) {
.kfa-card-stack-shuffle, .kfa-card-stack-shuffle *, .kfa-card-stack-shuffle::before, .kfa-card-stack-shuffle::after, .kfa-card-stack-shuffle *::before, .kfa-card-stack-shuffle *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--kfa-color on the element or a parent.
Currently previewing #3b82f6.--kfa-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.