25 CSS Spinners19 / 25

Pure CSSMIT licensed

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.

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-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;
  }
}
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: Breathing Circle Loader
Source: https://codefronts.com/motion/css-spinner-designs/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.
## HTML
```html
<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>
```
## CSS
```css
.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.

Make it yours

  • 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.

Gotchas — read before shipping

  • 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.

Techniques used in this demo

Search CodeFronts

Loading…