6 loading animations in pure CSS

Six loading animations, each one element (or a few dots) and a few lines of CSS. No images, no JavaScript.

UI loop

6 loading animations, pure CSS

Ring
Bounce
Equalizer
Ripple
Orbit
Morph
Sundry Millsundrymill.com/library
6 loading animations in pure CSS

Everything in the preview is live. Try it.

The code, one by one

Ring

The classic spinner: one coloured quarter going round.

HTML
<span class="ld-ring" role="status" aria-label="Loading"></span>
CSS
.ld-ring {
  display: inline-block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 5px solid rgba(23, 32, 44, .15);
  border-top-color: #FF7A2F;
  animation: ld-ring .9s linear infinite;
}
@keyframes ld-ring { to { transform: rotate(1turn); } }

Bounce

Three dots hop one after another, like someone typing.

HTML
<span class="ld-dots" role="status" aria-label="Loading"><i></i><i></i><i></i></span>
CSS
.ld-dots { display: inline-flex; gap: 8px; }
.ld-dots i {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #17202C;
  animation: ld-dots 1s cubic-bezier(.65, 0, .35, 1) infinite;
}
.ld-dots i:nth-child(2) { animation-delay: .15s; }
.ld-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes ld-dots {
  0%, 60%, 100% { transform: translateY(0); opacity: .45; }
  30% { transform: translateY(-12px); opacity: 1; }
}

Equalizer

Five bars rising and falling. Good for anything to do with sound.

HTML
<span class="ld-bars" role="status" aria-label="Loading"><i></i><i></i><i></i><i></i><i></i></span>
CSS
.ld-bars { display: inline-flex; align-items: center; gap: 5px; height: 40px; }
.ld-bars i {
  width: 6px;
  height: 100%;
  border-radius: 3px;
  background: #2F55D4;
  animation: ld-bars 1s ease-in-out infinite;
}
.ld-bars i:nth-child(2) { animation-delay: -.8s; }
.ld-bars i:nth-child(3) { animation-delay: -.6s; }
.ld-bars i:nth-child(4) { animation-delay: -.4s; }
.ld-bars i:nth-child(5) { animation-delay: -.2s; }
@keyframes ld-bars {
  0%, 100% { transform: scaleY(.3); }
  50% { transform: scaleY(1); }
}

Ripple

Two rings ripple outward. Calm, for longer waits.

HTML
<span class="ld-pulse" role="status" aria-label="Loading"></span>
CSS
.ld-pulse { position: relative; display: inline-block; width: 44px; height: 44px; }
.ld-pulse::before, .ld-pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 3px solid #FF7A2F;
  animation: ld-pulse 1.6s cubic-bezier(.05, .7, .1, 1) infinite;
}
.ld-pulse::after { animation-delay: .8s; }
@keyframes ld-pulse {
  from { transform: scale(.2); opacity: 1; }
  to { transform: scale(1); opacity: 0; }
}

Orbit

A dot circles a dashed track, like a small planet.

HTML
<span class="ld-orbit" role="status" aria-label="Loading"></span>
CSS
.ld-orbit {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 2px dashed rgba(23, 32, 44, .35);
  animation: ld-orbit 1.4s linear infinite;
}
.ld-orbit::after {
  content: "";
  position: absolute;
  top: -7px;
  left: 50%;
  width: 12px;
  height: 12px;
  margin-left: -6px;
  border-radius: 50%;
  background: #17202C;
}
@keyframes ld-orbit { to { transform: rotate(1turn); } }

Morph

A square turns a quarter and rounds into a circle, then back.

HTML
<span class="ld-morph" role="status" aria-label="Loading"></span>
CSS
.ld-morph {
  display: inline-block;
  width: 40px;
  height: 40px;
  border-radius: 4px;
  background: #FFB23F;
  animation: ld-morph 1.6s cubic-bezier(.65, 0, .35, 1) infinite;
}
@keyframes ld-morph {
  0%, 100% { border-radius: 4px; transform: rotate(0) scale(1); }
  50% { border-radius: 50%; transform: rotate(90deg) scale(.8); }
}

How to use it

  • Every loader carries role="status" and an aria-label, so a screen reader says "Loading" once instead of nothing.
  • Show a loader only after about 300 milliseconds. Fast responses then never flash a spinner at all.
  • Wrap the animations in a prefers-reduced-motion check if the wait can be long. A still ring with the word "Loading" is fine.

Showing an interaction like this to a client or in a tutorial? Framok records your screen and zooms in on every click for you.

Free to use in personal and commercial work. No credit needed, though a link back is always nice.

More from the library

See the whole library