AI CSS Animations

Card Deck Stacking

Four isometric UI cards slide in along the grid and stack into a deck on a spring, the top card tagged in the accent, then lift away. Hairline SVG slabs with CSS translate.

Also known as: stacked cards animation, card stack animation, hairline isometric.

HTML

<div class="hln-card-deck-stack" role="img" aria-label="Cards stacking into a deck">
  <svg viewBox="-110 -60 220 120" aria-hidden="true"><g transform="translate(0 8) scale(1.7)"><polygon class="hln-card-deck-stack-in" points="-5,-15.5 31,2.5 5,15.5 -31,-2.5"/><g class="hln-card-deck-stack-c0"><g><polygon points="-23,-2.5 5,11.5 5,9.9 -23,-4.1"/><polygon points="23,2.5 5,11.5 5,9.9 23,0.9"/><polygon points="-5,-13.1 23,0.9 5,9.9 -23,-4.1"/></g><ellipse class="hln-card-deck-stack-in" cx="-5.5" cy="-7.85" rx="3.11" ry="1.56"/><line class="hln-card-deck-stack-in" x1="0.5" y1="-5.85" x2="14.5" y2="1.15"/><line class="hln-card-deck-stack-in" x1="-2.5" y1="-4.35" x2="6.5" y2="0.15"/><line class="hln-card-deck-stack-in" x1="-14" y1="-4.6" x2="6" y2="5.4"/></g><g class="hln-card-deck-stack-c1"><g><polygon points="-23,-6.5 5,7.5 5,5.9 -23,-8.1"/><polygon points="23,-1.5 5,7.5 5,5.9 23,-3.1"/><polygon points="-5,-17.1 23,-3.1 5,5.9 -23,-8.1"/></g><ellipse class="hln-card-deck-stack-in" cx="-5.5" cy="-11.85" rx="3.11" ry="1.56"/><line class="hln-card-deck-stack-in" x1="0.5" y1="-9.85" x2="14.5" y2="-2.85"/><line class="hln-card-deck-stack-in" x1="-2.5" y1="-8.35" x2="6.5" y2="-3.85"/><line class="hln-card-deck-stack-in" x1="-14" y1="-8.6" x2="6" y2="1.4"/></g><g class="hln-card-deck-stack-c2"><g><polygon points="-23,-10.5 5,3.5 5,1.9 -23,-12.1"/><polygon points="23,-5.5 5,3.5 5,1.9 23,-7.1"/><polygon points="-5,-21.1 23,-7.1 5,1.9 -23,-12.1"/></g><ellipse class="hln-card-deck-stack-in" cx="-5.5" cy="-15.85" rx="3.11" ry="1.56"/><line class="hln-card-deck-stack-in" x1="0.5" y1="-13.85" x2="14.5" y2="-6.85"/><line class="hln-card-deck-stack-in" x1="-2.5" y1="-12.35" x2="6.5" y2="-7.85"/><line class="hln-card-deck-stack-in" x1="-14" y1="-12.6" x2="6" y2="-2.6"/></g><g class="hln-card-deck-stack-c3"><g><polygon points="-23,-14.5 5,-0.5 5,-2.1 -23,-16.1"/><polygon points="23,-9.5 5,-0.5 5,-2.1 23,-11.1"/><polygon points="-5,-25.1 23,-11.1 5,-2.1 -23,-16.1"/></g><ellipse class="hln-card-deck-stack-in" cx="-5.5" cy="-19.85" rx="3.11" ry="1.56"/><line class="hln-card-deck-stack-in" x1="0.5" y1="-17.85" x2="14.5" y2="-10.85"/><line class="hln-card-deck-stack-in" x1="-2.5" y1="-16.35" x2="6.5" y2="-11.85"/><line class="hln-card-deck-stack-in" x1="-14" y1="-16.6" x2="6" y2="-6.6"/><polygon class="hln-card-deck-stack-hot" points="-0.5,-8.35 5.5,-5.35 3.3,-4.25 -2.7,-7.25"/></g></g></svg>
</div>

CSS

.hln-card-deck-stack {
  --c: var(--hln-color, #ff4f2e);
  font-size: var(--hln-size, 16px);
  position: relative;
  display: grid;
  place-items: center;
  width: 22em;
  height: 12em;
  border-radius: 0.75em;
  background: #f6f5f1;
  overflow: hidden;
  --u: 1px;
}
.hln-card-deck-stack svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: #ffffff;
  stroke: #1c1d21;
  stroke-width: 1.25;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.hln-card-deck-stack svg * {
  vector-effect: non-scaling-stroke;
}
.hln-card-deck-stack .hln-card-deck-stack-in {
  stroke: #9a9ca3;
}
.hln-card-deck-stack .hln-card-deck-stack-hot {
  fill: var(--c);
  stroke: var(--c);
}
.hln-card-deck-stack .hln-card-deck-stack-c0 {
  animation: hln-card-deck-stack-c0 6s infinite;
}
.hln-card-deck-stack .hln-card-deck-stack-c1 {
  animation: hln-card-deck-stack-c1 6s infinite;
}
.hln-card-deck-stack .hln-card-deck-stack-c2 {
  animation: hln-card-deck-stack-c2 6s infinite;
}
.hln-card-deck-stack .hln-card-deck-stack-c3 {
  animation: hln-card-deck-stack-c3 6s infinite;
}
@keyframes hln-card-deck-stack-c0 {
  0%, 4% { translate: calc(34 * var(--u)) calc(17 * var(--u)); opacity: 0; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  8% { opacity: 1; }
  4.01% { translate: calc(34 * var(--u)) calc(17 * var(--u)); animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  11.7% { translate: calc(-2.72 * var(--u)) calc(-1.36 * var(--u)); animation-timing-function: ease-in-out; }
  15.2% { translate: calc(0.68 * var(--u)) calc(0.34 * var(--u)); animation-timing-function: ease-in-out; }
  18% { translate: 0 0; }
  80% { translate: 0 0; opacity: 1; animation-timing-function: ease-in; }
  88%, 100% { translate: 0 calc(-8 * var(--u)); opacity: 0; }
}
@keyframes hln-card-deck-stack-c1 {
  0%, 12% { translate: calc(34 * var(--u)) calc(17 * var(--u)); opacity: 0; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  16% { opacity: 1; }
  12.01% { translate: calc(34 * var(--u)) calc(17 * var(--u)); animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  19.7% { translate: calc(-2.72 * var(--u)) calc(-1.36 * var(--u)); animation-timing-function: ease-in-out; }
  23.2% { translate: calc(0.68 * var(--u)) calc(0.34 * var(--u)); animation-timing-function: ease-in-out; }
  26% { translate: 0 0; }
  77% { translate: 0 0; opacity: 1; animation-timing-function: ease-in; }
  85%, 100% { translate: 0 calc(-8 * var(--u)); opacity: 0; }
}
@keyframes hln-card-deck-stack-c2 {
  0%, 20% { translate: calc(34 * var(--u)) calc(17 * var(--u)); opacity: 0; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  24% { opacity: 1; }
  20.01% { translate: calc(34 * var(--u)) calc(17 * var(--u)); animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  27.7% { translate: calc(-2.72 * var(--u)) calc(-1.36 * var(--u)); animation-timing-function: ease-in-out; }
  31.2% { translate: calc(0.68 * var(--u)) calc(0.34 * var(--u)); animation-timing-function: ease-in-out; }
  34% { translate: 0 0; }
  74% { translate: 0 0; opacity: 1; animation-timing-function: ease-in; }
  82%, 100% { translate: 0 calc(-8 * var(--u)); opacity: 0; }
}
@keyframes hln-card-deck-stack-c3 {
  0%, 28% { translate: calc(34 * var(--u)) calc(17 * var(--u)); opacity: 0; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  32% { opacity: 1; }
  28.01% { translate: calc(34 * var(--u)) calc(17 * var(--u)); animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  35.7% { translate: calc(-2.72 * var(--u)) calc(-1.36 * var(--u)); animation-timing-function: ease-in-out; }
  39.2% { translate: calc(0.68 * var(--u)) calc(0.34 * var(--u)); animation-timing-function: ease-in-out; }
  42% { translate: 0 0; }
  71% { translate: 0 0; opacity: 1; animation-timing-function: ease-in; }
  79%, 100% { translate: 0 calc(-8 * var(--u)); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .hln-card-deck-stack * {
    animation: none !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hln-card-deck-stack, .hln-card-deck-stack *, .hln-card-deck-stack::before, .hln-card-deck-stack::after, .hln-card-deck-stack *::before, .hln-card-deck-stack *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --hln-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --hln-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar hairline animations