25 CSS Spinners03 / 25

Pure CSSMIT licensed

Dot Chase Orbit Spinner

Four multi-coloured dots orbit a shared centre, each fading in and out with staggered delays to create a chasing, comet-like orbital trail effect.

Published

Live Demo
Try it

This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.

The code

<div class="sp-03">
  <div class="sp-03__orbit">
    <div class="sp-03__trail"></div>
    <div class="sp-03__dot"></div>
    <div class="sp-03__dot"></div>
    <div class="sp-03__dot"></div>
    <div class="sp-03__dot"></div>
  </div>
</div>
.sp-03,
.sp-03 *,
.sp-03 *::before,
.sp-03 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.sp-03 {
  --bg: #0b1120;
  --d1: #f9a825;
  --d2: #ff6b35;
  --d3: #e91e8c;
  --d4: #7c4dff;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--bg);
}

.sp-03__orbit {
  position: relative;
  width: 72px;
  height: 72px;
  animation: sp-03-spin 1.4s linear infinite;
}

.sp-03__dot {
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  top: 50%;
  left: 50%;
  transform-origin: 0 0;
}

.sp-03__dot:nth-child(1) {
  background: var(--d1);
  box-shadow: 0 0 8px var(--d1);
  transform: rotate(0deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: 0s;
}

.sp-03__dot:nth-child(2) {
  background: var(--d2);
  box-shadow: 0 0 8px var(--d2);
  transform: rotate(90deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: -0.35s;
}

.sp-03__dot:nth-child(3) {
  background: var(--d3);
  box-shadow: 0 0 8px var(--d3);
  transform: rotate(180deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: -0.7s;
}

.sp-03__dot:nth-child(4) {
  background: var(--d4);
  box-shadow: 0 0 8px var(--d4);
  transform: rotate(270deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: -1.05s;
}

.sp-03__trail {
  position: absolute;
  inset: 8px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.06);
}

@keyframes sp-03-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes sp-03-fade {
  0%,
    100% {
    opacity: 1;
    transform-origin: 0 0;
  }

  50% {
    opacity: 0.25;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sp-03__orbit,
    .sp-03__dot {
    animation: none;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Spinner from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Dot Chase Orbit Spinner
Source: https://codefronts.com/motion/css-spinner-designs/dot-chase-orbit-spinner/

Four multi-coloured dots orbit a shared centre, each fading in and out with staggered delays to create a chasing, comet-like orbital trail effect.
## HTML
```html
<div class="sp-03">
  <div class="sp-03__orbit">
    <div class="sp-03__trail"></div>
    <div class="sp-03__dot"></div>
    <div class="sp-03__dot"></div>
    <div class="sp-03__dot"></div>
    <div class="sp-03__dot"></div>
  </div>
</div>
```
## CSS
```css
.sp-03,
.sp-03 *,
.sp-03 *::before,
.sp-03 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.sp-03 {
  --bg: #0b1120;
  --d1: #f9a825;
  --d2: #ff6b35;
  --d3: #e91e8c;
  --d4: #7c4dff;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--bg);
}

.sp-03__orbit {
  position: relative;
  width: 72px;
  height: 72px;
  animation: sp-03-spin 1.4s linear infinite;
}

.sp-03__dot {
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  top: 50%;
  left: 50%;
  transform-origin: 0 0;
}

.sp-03__dot:nth-child(1) {
  background: var(--d1);
  box-shadow: 0 0 8px var(--d1);
  transform: rotate(0deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: 0s;
}

.sp-03__dot:nth-child(2) {
  background: var(--d2);
  box-shadow: 0 0 8px var(--d2);
  transform: rotate(90deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: -0.35s;
}

.sp-03__dot:nth-child(3) {
  background: var(--d3);
  box-shadow: 0 0 8px var(--d3);
  transform: rotate(180deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: -0.7s;
}

.sp-03__dot:nth-child(4) {
  background: var(--d4);
  box-shadow: 0 0 8px var(--d4);
  transform: rotate(270deg) translateX(28px) translateY(-6px);
  animation: sp-03-fade 1.4s linear infinite;
  animation-delay: -1.05s;
}

.sp-03__trail {
  position: absolute;
  inset: 8px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.06);
}

@keyframes sp-03-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes sp-03-fade {
  0%,
    100% {
    opacity: 1;
    transform-origin: 0 0;
  }

  50% {
    opacity: 0.25;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sp-03__orbit,
    .sp-03__dot {
    animation: none;
  }
}
```

How this works

Each dot is absolutely positioned at the centre (top:50%;left:50%) with transform-origin:0 0, then pushed outward with translateX(28px) after a fixed rotate(Ndeg) — so all four sit at 0°, 90°, 180°, and 270° on the same orbit radius. The parent .sp-03__orbit div spins continuously with sp-03-spin, carrying the dots with it.

A second separate sp-03-fade keyframe on each dot drives opacity between 1 and 0.25, offset by animation-delay in 0.35 s steps, so whichever dot is at the "front" position appears brightest, simulating a directional chase trail.

Make it yours

  • Edit --d1 through --d4 to change the four dot colours independently.
  • Increase the orbit radius from translateX(28px) to 36px for a wider sweep around a larger central element.
  • Add a fifth dot at rotate(216deg) and set animation-delay:-1.12s to extend the chase to a pentagon orbit.
  • Change dot size from 12px to 8px with a longer trail delay (0.45s steps) for a tighter comet appearance.
  • Adjust the parent spin duration (default 1.4s) to control overall speed — the fade delays scale automatically since they are set in absolute seconds.

Gotchas — read before shipping

  • The transform-origin:0 0 trick means that changing the dot's width or height shifts its radial distance — always re-check orbit radius after resizing dots.
  • Negative animation-delay values are used for the fade — this is valid per the spec but Safari below v14 occasionally mis-renders the first frame; add a tiny animation-fill-mode:backwards as a workaround.
  • Rotating the parent while each child also animates opacity can compound GPU layer creation — keep the child opacity animation on will-change:opacity if you see compositing budget warnings.

Browser support

ChromeSafariFirefoxEdge
60+12+60+60+

Uses only transform and opacity animations; compositor-friendly on all modern browsers.

Techniques used in this demo

Search CodeFronts

Loading…