Pure CSS Loaders & patterns #loop #loader

Gyroscope in pure CSS

Three nested rings, each spinning on a single axis — the rotations compound.

  • 62 lines of CSS
  • 9 lines of HTML
  • No JavaScript
  • No dependencies
  • Snippet under MIT
GitHub

How it works

  1. Three rings, nested. Each spins around one axis only.
  2. Because a child lives inside its parent’s coordinate space, the rotations stack up into complex motion from trivially simple keyframes.
  3. Every level needs transform-style: preserve-3d or the chain flattens there.
  4. Unequal durations keep the pattern from visibly repeating.
  5. A flat disc seen edge-on draws nothing, so the glowing core is four discs crossed through one centre (three turned round the vertical by 60deg each, one laid flat): however the rings turn it, one of them faces you.
  6. The outer ring is 220 units of one base unit, --u, tied to the canvas, and each ring inside is 84% of the one around it, so the whole gyroscope is the same share of a gallery card, the editor and a recording canvas.

Key techniques

  • nested preserve-3d
  • one axis per level
  • different durations

Copy-paste code

HTML 9 lines

<div class="scene">
  <div class="gyro">
    <div>
      <div>
        <b><i style="--i:0"></i><i style="--i:1"></i><i style="--i:2"></i><i></i></b>
      </div>
    </div>
  </div>
</div>

CSS 62 lines

.scene {
  /* one base unit: every length below is a multiple of it, so the gyroscope is the same share of
     a gallery card, the editor, a full screen and a recording canvas */
  --u: 0.24vmin;
  perspective: calc(800 * var(--u));
}

.gyro,
.gyro div {
  box-sizing: content-box; /* each ring is 84% of the inside of the one round it: by design, on any page */
  display: grid;
  place-items: center;
  border: calc(4 * var(--u)) solid #8b6cff;
  border-radius: 50%;
  transform-style: preserve-3d;
}

.gyro {
  width: calc(220 * var(--u));
  height: calc(220 * var(--u));
  animation: gyro-x 6s linear infinite;
}

.gyro div {
  width: 84%;
  height: 84%;
}

.gyro > div {
  border-color: #2ee6d6;
  animation: gyro-y 4s linear infinite;
}

.gyro > div > div {
  border-color: #ff4d9d;
  animation: gyro-x 2.6s linear infinite reverse;
}

/* the core: a flat disc seen edge-on draws nothing, so it is four glowing discs crossed through
   one centre, three turned round the vertical and one laid flat. Whichever way the rings turn
   it, at least one of them faces you. */
.gyro b {
  position: relative;
  width: 34%;
  height: 34%;
  transform-style: preserve-3d;
}

.gyro b i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, #fff, #ffb547 50%, rgb(255 181 71 / 0.35) 72%, rgb(255 181 71 / 0) 100%);
  transform: rotateY(calc(var(--i) * 60deg));
}

.gyro b i:last-child {
  transform: rotateX(90deg);
}

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