Hover card fan
Pure CSSThree overlapping cards: the one you point at straightens and comes toward you while the others dim and lean away. Static strips catch the pointer, so nothing flickers.
Five cards share one pivot below the hand and fan out by index.
Your edited version
transform-origin: 50% 170% moves the pivot far below the card, so rotateZ swings it along an arc instead of spinning it in place.rotateZ(calc(var(--i) * 16deg)) fans symmetrically around an upright middle card.translateZ per card gives each its own depth, which avoids flicker where they overlap.transform-origin far below the cardrotateZ(var(--i) × step)translateZ per card to avoid z-fighting<div class="scene">
<div class="hand">
<i style="--i:-2">A<small>♠</small></i>
<i style="--i:-1">K<small>♠</small></i>
<i style="--i:0">Q<small>♠</small></i>
<i style="--i:1">J<small>♠</small></i>
<i style="--i:2">10<small>♠</small></i>
</div>
</div>
.scene {
perspective: 800px;
}
.hand {
position: relative;
width: 110px;
height: 156px;
transform-style: preserve-3d;
transform: rotateX(26deg);
}
.hand i {
position: absolute;
inset: 0;
padding: 8px 12px;
border-radius: 10px;
background: linear-gradient(160deg, #fff, #d9dcec);
color: #14172b;
font: 800 1.6rem/1 system-ui;
box-shadow: 0 8px 16px -8px #000;
transform-origin: 50% 170%;
animation: fan 3s ease-in-out infinite alternate;
}
.hand small { display: block; font-size: 1.2rem; }
@keyframes fan {
0%, 15% { transform: translateZ(calc(var(--i) * 1px)) rotateZ(0deg); }
85%, 100% { transform: translateZ(calc(var(--i) * 6px)) rotateZ(calc(var(--i) * 16deg)); }
}
.d-cardfan {
position: relative;
width: 84px;
height: 120px;
transform-style: preserve-3d;
transform: translateY(10px) rotateX(26deg);
// --i runs -2…2 from the markup, so the middle card stays upright.
i {
position: absolute;
inset: 0;
padding: 6px 9px;
border-radius: 9px;
background: linear-gradient(160deg, #fff, #d9dcec);
color: #14172b;
font-size: 20px;
font-style: normal;
font-weight: 800;
line-height: 1;
box-shadow: 0 8px 16px -8px #000;
// The pivot sits well below the card, like the wrist holding the hand.
transform-origin: 50% 170%;
animation: d-cardfan 3s ease-in-out infinite alternate;
small {
display: block;
font-size: 16px;
}
}
}
@keyframes d-cardfan {
0%,
15% {
transform: translateZ(calc(var(--i) * 1px)) rotateZ(0deg);
}
85%,
100% {
transform: translateZ(calc(var(--i) * 6px)) rotateZ(calc(var(--i) * 16deg));
}
}