Pure CSS Text effects #loop #text

Text ring in pure CSS

A sentence wrapped around a cylinder, one character per slice.

  • 27 lines of CSS
  • 28 lines of HTML
  • No JavaScript
  • No dependencies
  • MIT licensed
GitHub

How it works

  1. One <span> per character, all stacked in the same spot.
  2. Each gets rotateY(i × 360° / count) translateZ(radius) — the carousel formula again.
  3. backface-visibility: hidden hides the far side, where letters would otherwise show mirrored.
  4. A monospace font keeps the spacing even. Pick the radius so that 2πr ≈ count × character width.

Key techniques

  • rotateY(i × 360° / n) translateZ(r)
  • backface-visibility: hidden
  • monospace for even spacing

Copy-paste code

HTML 28 lines

<div class="scene">
  <div class="ring" style="--n:24" aria-label="CSS 3D LAB • NO WEBGL •">
    <span style="--i:0" aria-hidden="true">C</span>
    <span style="--i:1" aria-hidden="true">S</span>
    <span style="--i:2" aria-hidden="true">S</span>
    <span style="--i:3" aria-hidden="true">&nbsp;</span>
    <span style="--i:4" aria-hidden="true">3</span>
    <span style="--i:5" aria-hidden="true">D</span>
    <span style="--i:6" aria-hidden="true">&nbsp;</span>
    <span style="--i:7" aria-hidden="true">L</span>
    <span style="--i:8" aria-hidden="true">A</span>
    <span style="--i:9" aria-hidden="true">B</span>
    <span style="--i:10" aria-hidden="true">&nbsp;</span>
    <span style="--i:11" aria-hidden="true"></span>
    <span style="--i:12" aria-hidden="true">&nbsp;</span>
    <span style="--i:13" aria-hidden="true">N</span>
    <span style="--i:14" aria-hidden="true">O</span>
    <span style="--i:15" aria-hidden="true">&nbsp;</span>
    <span style="--i:16" aria-hidden="true">W</span>
    <span style="--i:17" aria-hidden="true">E</span>
    <span style="--i:18" aria-hidden="true">B</span>
    <span style="--i:19" aria-hidden="true">G</span>
    <span style="--i:20" aria-hidden="true">L</span>
    <span style="--i:21" aria-hidden="true">&nbsp;</span>
    <span style="--i:22" aria-hidden="true"></span>
    <span style="--i:23" aria-hidden="true">&nbsp;</span>
  </div>
</div>

CSS 27 lines

.scene {
  perspective: 800px;
}

.ring {
  --r: 125px;
  position: relative;
  width: 26px;
  height: 44px;
  font: 800 2.1rem ui-monospace, monospace;
  transform-style: preserve-3d;
  animation: ring-spin 12s linear infinite;
}

.ring span {
  position: absolute;
  inset: 0;
  text-align: center;
  color: #2ee6d6;
  backface-visibility: hidden;
  transform: rotateY(calc(var(--i) * 360deg / var(--n))) translateZ(var(--r));
}

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

Sass source 31 lines

.d-textring {
  --r: 92px;
  position: relative;
  width: 20px;
  height: 34px;
  font-family: var(--mono);
  font-size: 26px;
  font-weight: 800;
  transform-style: preserve-3d;
  animation: d-textring-spin 12s linear infinite;

  // --n (character count) and --i (index) come from the markup.
  span {
    position: absolute;
    inset: 0;
    text-align: center;
    color: var(--accent-2);
    backface-visibility: hidden; // hide the mirrored letters on the far side
    transform: rotateY(calc(var(--i) * 360deg / var(--n))) translateZ(var(--r));
  }
}

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

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