AI CSS Animations

Orbiting Words Ring

A tilted ring of words circles a bold center word in 3D, passing in front and behind it, fading as each word goes round the back. One registered angle turns the ring and keeps every word facing you.

Also known as: 3d spinning text ring, text orbit animation css, words rotating around text, 3d text carousel.

HTML

<div class="txt-orbiting-word-ring" aria-label="Stack: Auth, Billing, Search, Email, Storage, Analytics">
  <span class="txt-orbiting-word-ring-ring" aria-hidden="true"><b>Stack</b><span style="--i: 0">Auth</span><span style="--i: 1">Billing</span><span style="--i: 2">Search</span><span style="--i: 3">Email</span><span style="--i: 4">Storage</span><span style="--i: 5">Analytics</span></span>
</div>

CSS

@property --txt-orbiting-word-ring-a {
  syntax: "<angle>";
  inherits: true;
  initial-value: 0deg;
}
.txt-orbiting-word-ring {
  --c: var(--txt-color, #3b82f6);
  font-size: var(--txt-size, 32px);
  font-family: system-ui, sans-serif;
  font-weight: 700;
  line-height: 1.2;
  display: grid;
  place-items: center;
  width: 15.4em;
  height: 6.4em;
  perspective: 22em;}
.txt-orbiting-word-ring-ring {
  position: relative;
  transform-style: preserve-3d;
  transform: rotateX(72deg) rotateZ(var(--txt-orbiting-word-ring-a));
  animation: txt-orbiting-word-ring-turn 18s linear infinite;
}
/* the orbit itself: a circle in the tilted plane reads as an ellipse */
.txt-orbiting-word-ring-ring::before {
  content: "";
  position: absolute;
  left: -5.6em;
  top: -5.6em;
  width: 11.2em;
  height: 11.2em;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--c) 40%, transparent);
}
.txt-orbiting-word-ring-ring b,
.txt-orbiting-word-ring-ring span {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  transform-origin: 0 0;
}
.txt-orbiting-word-ring-ring b {
  font-size: 1.5em;
  font-weight: 800;
  letter-spacing: -0.02em;
  transform: rotateZ(calc(-1 * var(--txt-orbiting-word-ring-a))) rotateX(-72deg) translate(-50%, -50%);
}
.txt-orbiting-word-ring-ring span {
  font-size: 0.78em;
  font-weight: 600;
  color: var(--c);
  /* out to the orbit, then undo the spin and the tilt so the word faces you */
  transform:
    rotateZ(calc(var(--i) * 60deg)) translateY(-7.18em)
    rotateZ(calc(var(--i) * -60deg - var(--txt-orbiting-word-ring-a))) rotateX(-72deg) translate(-50%, -50%);
  opacity: calc(0.62 - 0.38 * cos(var(--i) * 60deg + var(--txt-orbiting-word-ring-a)));
}
@keyframes txt-orbiting-word-ring-turn {
  to { --txt-orbiting-word-ring-a: 360deg; }
}
@media (prefers-reduced-motion: reduce) {
  .txt-orbiting-word-ring-ring { animation: none; --txt-orbiting-word-ring-a: 30deg; }
}

@media (prefers-reduced-motion: reduce) {
  .txt-orbiting-word-ring, .txt-orbiting-word-ring *, .txt-orbiting-word-ring::before, .txt-orbiting-word-ring::after, .txt-orbiting-word-ring *::before, .txt-orbiting-word-ring *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --txt-color on the element or a parent. Currently previewing #3b82f6.
  • Font size: set --txt-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 40px.
  • 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 text animations