Opent in een nieuw tabblad

CSS-lab · Loaders

Orbit-loader

Twee lichtgevende stippen met een vervagende trail draaien in tegengestelde banen om een pulserende acid kern. Pure CSS met conic-gradient en mask.

  • Gevorderd
  • Pure CSS
  • MIT-licentie
  • conic-gradient
  • mask
  • radial-gradient
  • @keyframes
  • animation-direction
HTML
<div class="ol-loader" role="status">
  <span class="ol-ring ol-ring--a" aria-hidden="true"><span class="ol-dot"></span></span>
  <span class="ol-ring ol-ring--b" aria-hidden="true"><span class="ol-dot"></span></span>
  <span class="ol-core" aria-hidden="true"></span>
  <span class="ol-sr">Bezig met laden</span>
</div>
CSS
/* Orbit-loader — prefix .ol- */
.ol-loader {
  --size: 112px;
  --track: 3px;
  --c1: #C6FF3D;
  --c2: #9B5CFF;
  --core: #C6FF3D;
  --speed: 1.6s;
  position: relative;
  display: grid;
  place-items: center;
  width: var(--size);
  height: var(--size);
}

/* draaiende baan (draagt de stip) */
.ol-ring {
  position: absolute;
  inset: 0;
  animation: ol-spin var(--speed) linear infinite;
}

/* vervagende trail, gemaskt tot een dunne ring */
.ol-ring::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--trail);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--track)), #000 calc(100% - var(--track) + 1px));
  mask: radial-gradient(farthest-side, transparent calc(100% - var(--track)), #000 calc(100% - var(--track) + 1px));
}

.ol-ring--a {
  --c: var(--c1);
  --trail: conic-gradient(from 0deg, transparent 0 55%, var(--c) 100%);
}

/* binnenbaan: kleiner, gespiegelde trail, tegengesteld */
.ol-ring--b {
  --c: var(--c2);
  --trail: conic-gradient(from 0deg, var(--c) 0%, transparent 45% 100%);
  inset: calc(var(--size) * .2);
  animation-duration: calc(var(--speed) * .7);
  animation-direction: reverse;
}

/* stip op de baan, bovenaan */
.ol-dot {
  position: absolute;
  top: calc(var(--track) / 2);
  left: 50%;
  width: calc(var(--track) * 3.4);
  height: calc(var(--track) * 3.4);
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 8px var(--c), 0 0 18px var(--c);
  transform: translate(-50%, -50%);
}

/* pulserende kern */
.ol-core {
  width: calc(var(--size) * .16);
  height: calc(var(--size) * .16);
  border-radius: 50%;
  background: var(--core);
  animation: ol-pulse calc(var(--speed) * 1.25) ease-in-out infinite;
}

@keyframes ol-spin {
  to { transform: rotate(1turn); }
}

@keyframes ol-pulse {
  0%, 100% {
    transform: scale(.85);
    box-shadow: 0 0 0 0 rgba(198, 255, 61, .45);
  }
  50% {
    transform: scale(1);
    box-shadow: 0 0 0 10px rgba(198, 255, 61, 0);
  }
}

/* tekst alleen voor screenreaders */
.ol-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .ol-ring { animation-duration: calc(var(--speed) * 4); }
  .ol-ring--b { animation-duration: calc(var(--speed) * 2.8); }
  .ol-core { animation: none; }
}

Wat het is en waar je het gebruikt

Deze orbit-loader ziet eruit als een klein zonnestelsel. In het midden pulseert een acid kern, daaromheen draaien twee stippen: de buitenste in acid met de klok mee, de binnenste in sunset violet ertegenin. Achter elke stip trekt een staart die geleidelijk vervaagt, zoals een komeet. Doordat de banen een verschillende snelheid hebben, ontstaat er nooit een saai, voorspelbaar patroon.

Hij past bij het laden van data, het verwerken van een upload, een AI-antwoord dat wordt gegenereerd of een splashscreen. Op een donkere achtergrond komt de glow het best tot zijn recht.

Zo werkt het

  • De trail: het ::before van elke .ol-ring krijgt een conic-gradient die van transparant naar de stipkleur loopt. Een mask met een radial-gradient houdt daar alleen een dunne ring van over, waardoor de gradient als een vervagende staart langs de baan ligt.
  • De stip: .ol-dot staat bovenaan de ring, precies waar de gradient het felst is. Een dubbele box-shadow geeft hem een glow. Omdat het masker alleen op het pseudo-element zit, wordt de glow niet afgeknipt, en omdat de stip een kind van de ring is, draait hij gewoon mee.
  • Tegengesteld: beide ringen gebruiken @keyframes ol-spin. De binnenste ring heeft animation-direction: reverse en een gespiegelde conic-gradient, zodat de staart ook bij de omgekeerde draairichting achter de stip blijft.
  • De kern: .ol-core pulseert met @keyframes ol-pulse in scale en een uitdijende box-shadow.

Aanpassen

Op .ol-loader staan --size (totale diameter), --track (dikte van de trail), --c1 en --c2 (kleuren van de buitenste en binnenste baan), --core en --speed. De binnenste baan draait op 70% van --speed; pas die factor aan in .ol-ring--b voor een ander ritme. Alle maten zijn afgeleid van --size en --track, dus je kunt de loader zonder gedoe schalen.

Toegankelijkheid en browsersupport

De loader heeft role="status" met een visueel verborgen tekst “Bezig met laden”; de ringen, stippen en kern zijn aria-hidden="true". Met prefers-reduced-motion: reduce draaien de banen vier keer zo langzaam en stopt de puls, zodat er rustig iets beweegt zonder onrust. conic-gradient en mask werken in alle actuele browsers; voor oudere Safari staat -webkit-mask erbij.

Verder lezen

Laadmomenten zijn microinteracties die het gevoel van snelheid bepalen. Hoe je ze ontwerpt, lees je in microinteracties in UX. Meer kinetische details voor je eigen site vind je bij interactief webdesign en animaties.