25 CSS Spinners 19 / 25

Breathing Circle Loader

A calm azure orb slowly inhales and exhales with a scale pulse while three expanding rings propagate outward in a continuous ripple, creating a meditative loading state.

Pure CSS MIT licensed
Live Demo Open in tab

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

Open in playground

The code

<div class="sp-19">
  <div class="sp-19__wrap">
    <div class="sp-19__ring"></div>
    <div class="sp-19__ring"></div>
    <div class="sp-19__ring"></div>
    <div class="sp-19__core"></div>
  </div>
  <div class="sp-19__label">Loading</div>
</div>
.sp-19,.sp-19 *,.sp-19 *::before,.sp-19 *::after{box-sizing:border-box;margin:0;padding:0}
.sp-19{
  --bg:#03080e;
  --c:#4fc3f7;
  --glow:rgba(79,195,247,0.3);
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:20px;
  min-height:100vh;
  background:var(--bg);
  font-family:system-ui,sans-serif;
}
.sp-19__wrap{
  position:relative;
  width:90px;
  height:90px;
}
.sp-19__ring{
  position:absolute;
  border-radius:50%;
  border:2px solid var(--c);
  opacity:0;
  animation:sp-19-breathe-ring 4s ease-in-out infinite;
}
.sp-19__ring:nth-child(1){inset:0}
.sp-19__ring:nth-child(2){inset:0;animation-delay:1.3s}
.sp-19__ring:nth-child(3){inset:0;animation-delay:2.6s}
.sp-19__core{
  position:absolute;
  inset:20px;
  border-radius:50%;
  background:radial-gradient(circle,var(--c),rgba(79,195,247,0.3));
  animation:sp-19-breathe-core 4s ease-in-out infinite;
}
.sp-19__label{
  color:rgba(79,195,247,0.7);
  font-size:11px;
  letter-spacing:3px;
  text-transform:uppercase;
  animation:sp-19-text 4s ease-in-out infinite;
}
@keyframes sp-19-breathe-ring{
  0%{transform:scale(0.4);opacity:0.8}
  100%{transform:scale(1.8);opacity:0}
}
@keyframes sp-19-breathe-core{
  0%,100%{transform:scale(0.7);box-shadow:0 0 10px var(--glow)}
  50%{transform:scale(1.15);box-shadow:0 0 30px var(--glow),0 0 60px var(--glow)}
}
@keyframes sp-19-text{
  0%,100%{opacity:0.3}
  50%{opacity:1}
}
@media (prefers-reduced-motion: reduce){
  .sp-19__ring,.sp-19__core,.sp-19__label{animation:none;opacity:1}
}

How this works

The core element runs sp-19-breathe-core: a 4-second ease-in-out cycle from scale(0.7) to scale(1.15) and back, with a simultaneously-animated box-shadow glow that expands from a tight to a diffuse halo — mimicking the glow intensifying on the exhale. The 4-second duration is chosen to match a typical adult breathing cycle, making the animation feel physiologically grounded.

Three rings run sp-19-breathe-ring each starting at scale(0.4) with 0.8 opacity and expanding to scale(1.8) at zero opacity. Offset by 1.3s each (one-third of the 4s period), they create a constant outward propagation that mirrors the core's exhale rhythm.

Customize

  • Edit --c to change the orb colour — a warm amber creates a candle-flame breathing loader; deep green suits wellness or eco-themed apps.
  • Change the duration from 4s to 6s for a slower, deeper breathing pace, or 2s for a quicker cadence suitable as an active spinner.
  • Increase ring scale from 1.8 to 2.5 for wider propagation — useful over large modal overlays.
  • Add a text label that fades between "Loading…" and "Please wait…" using a separate opacity keyframe on a sibling element.
  • Reduce to one ring by removing two .sp-19__ring elements for a minimal meditative pulse without the ripple effect.

Watch out for

  • The 4s duration with three rings offset by 1.3s leaves a small phase error (3 × 1.3 = 3.9s, not 4s) — rings gradually drift over many cycles; use 1.333s delay to keep them in phase.
  • box-shadow changes in keyframes are not composited and trigger a repaint on each frame — switch to a pseudo-element with a scale/opacity animation for a compositor-only approach.
  • The Loading text label uses letter-spacing animation for effect — this is not compositor-friendly; if FPS is critical, remove the label animation.

Browser support

ChromeSafariFirefoxEdge
60+ 12+ 60+ 60+

Widely supported; box-shadow animation in keyframes triggers repaint but is acceptable for a single-instance spinner.

Search CodeFronts

Loading…