Pure CSS Shapes & solids #loop #shape

Wireframe globe in pure CSS

Nine circles rotated around the Y axis make the meridians; one laid flat is the equator.

  • 36 lines of CSS
  • 14 lines of HTML
  • No JavaScript
  • No dependencies
  • Snippet under MIT
GitHub

How it works

  1. A circle is a square with border-radius: 50% and only an edge line. The line is an inset box-shadow with a soft glow, not a border: a ring turned nearly side-on is squeezed to a pixel or two, and a hard 1.5px border breaks into dots there.
  2. Nine of them, rotated i × 20deg around Y, form the meridians. 9 × 20° = 180° is enough because each ring is visible on both sides.
  3. One more ring laid flat with rotateX(90deg) is the equator.
  4. A static rotateZ before the animated rotateY gives the tilted-axis look.
  5. Every length is a multiple of one base unit, --u, so the globe is the same share of a gallery card, the editor and a recording canvas. The sphere is 200 of those units across, and the camera sits 800 back — close enough that the near side is magnified, which is what the base unit has to leave room for.

Key techniques

  • border-radius: 50% rings
  • rotateY(i × 20deg)
  • preserve-3d spin

Copy-paste code

HTML 14 lines

<div class="scene">
  <div class="globe">
    <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>
    <i style="--i:7"></i>
    <i style="--i:8"></i>
    <b></b>
  </div>
</div>

CSS 36 lines

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

.globe {
  position: relative;
  width: calc(200 * var(--u));
  height: calc(200 * var(--u));
  transform-style: preserve-3d;
  animation: globe-spin 14s linear infinite;
}

/* the line is an inset shadow with a soft glow, not a border: a ring nearly side-on is squeezed
   to a pixel or two, and a hard border breaks into dots there. The glow keeps it whole. */
.globe i,
.globe b {
  --c: #2ee6d6;
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow:
    inset 0 0 0 calc(1.5 * var(--u)) var(--c),
    inset 0 0 calc(2 * var(--u)) calc(1.5 * var(--u)) color-mix(in srgb, var(--c) 40%, transparent),
    0 0 calc(2 * var(--u)) color-mix(in srgb, var(--c) 50%, transparent);
}

.globe i { transform: rotateY(calc(var(--i) * 20deg)); }   /* meridians */
.globe b { transform: rotateX(90deg); --c: #ff4d9d; }       /* equator */

@keyframes globe-spin {
  from { transform: rotateZ(18deg) rotateX(-14deg) rotateY(0deg); }
  to   { transform: rotateZ(18deg) rotateX(-14deg) rotateY(360deg); }
}
Standalone snippet · plain CSS, no build step, no dependencies.