Pure CSS Shapes & solids #loop #shape

Spinning coin in pure CSS

Two faces plus a stack of thin discs between them to fake a solid edge.

  • 44 lines of CSS
  • 13 lines of HTML
  • No JavaScript
  • No dependencies
  • MIT licensed

How it works

  1. Front and back are two discs pushed apart with translateZ(±5px); the back one is pre-flipped with rotateY(180deg).
  2. backface-visibility: hidden stops you seeing the front face through the back.
  3. A flat disc has no edge, so seven plain discs are stacked between the faces. Edge-on, they merge into a solid rim.
  4. Spin the parent. That is all.

Key techniques

  • stacked translateZ layers
  • backface-visibility
  • rotateY spin

Copy-paste code

HTML 13 lines

<div class="scene">
  <div class="coin">
    <b>$</b>
    <i style="--i:0"></i>
    <i style="--i:1"></i>
    <i style="--i:2"></i>
    <i style="--i:3"></i>
    <i style="--i:4"></i>
    <i style="--i:5"></i>
    <i style="--i:6"></i>
    <b></b>
  </div>
</div>

CSS 44 lines

.scene {
  perspective: 800px;
}

.coin {
  position: relative;
  width: 150px;
  height: 150px;
  transform-style: preserve-3d;
  animation: coin-spin 4s linear infinite;
}

.coin b,
.coin i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

/* the rim: 7 discs spread from -4.2px to +4.2px */
.coin i {
  background: #a8741a;
  transform: translateZ(calc((var(--i) - 3) * 1.4px));
}

.coin b {
  display: grid;
  place-items: center;
  border: 6px solid #e2a93b;
  background: radial-gradient(circle at 35% 30%, #fff1b8, #f1b93d 55%, #c98a1b);
  color: #8a5a0c;
  font: 900 4.5rem system-ui;
  backface-visibility: hidden;
  transform: translateZ(5px);
}

.coin b:last-child {
  transform: rotateY(180deg) translateZ(5px);
}

@keyframes coin-spin {
  from { transform: rotateX(12deg) rotateY(0deg); }
  to   { transform: rotateX(12deg) rotateY(360deg); }
}

Sass source 48 lines

$size: 120px;
$half-thickness: 5px;

.d-coin {
  position: relative;
  width: $size;
  height: $size;
  transform-style: preserve-3d;
  animation: d-coin-spin 4s linear infinite;

  b,
  i {
    position: absolute;
    inset: 0;
    border-radius: 50%;
  }

  // The "edge": seven plain discs spread between the two faces. --i is 0…6.
  i {
    background: #a8741a;
    transform: translateZ(calc((var(--i) - 3) * 1.4px));
  }

  b {
    display: grid;
    place-items: center;
    border: 5px solid #e2a93b;
    background: radial-gradient(circle at 35% 30%, #fff1b8, #f1b93d 55%, #c98a1b);
    color: #8a5a0c;
    font-size: 58px;
    backface-visibility: hidden;
    transform: translateZ($half-thickness);

    &:last-child {
      transform: rotateY(180deg) translateZ($half-thickness);
    }
  }
}

@keyframes d-coin-spin {
  from {
    transform: rotateX(12deg) rotateY(0deg);
  }

  to {
    transform: rotateX(12deg) rotateY(360deg);
  }
}
Standalone snippet · plain CSS, no build step, no dependencies.