Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to make a loading spinner

Short answer

A circle with one colored side of its border, spinning forever:

<style>
  @keyframes spin { to { rotate: 1turn; } }
  .spinner { width: 40px; height: 40px; border: 4px solid gainsboro; border-top-color: royalblue; border-radius: 50%; animation: spin 0.8s linear infinite; }
</style>
 
<div class="spinner" role="status" aria-label="Loading"></div>

linear gives an even speed with no jerks, and infinite repeats the animation forever.

Three dots

Another popular variant is dots that bounce one after another. One animation with different delays:

<style>
  @keyframes bounce { 50% { translate: 0 -8px; opacity: 0.4; } }
  .dots { display: flex; gap: 6px; padding: 16px; }
  .dots span { width: 10px; height: 10px; border-radius: 50%; background: seagreen; animation: bounce 0.9s infinite; }
  .dots span:nth-child(2) { animation-delay: 0.15s; }
  .dots span:nth-child(3) { animation-delay: 0.3s; }
</style>
 
<div class="dots" role="status" aria-label="Loading"><span></span><span></span><span></span></div>

Accessibility

role="status" and aria-label tell a screen reader that something is loading — otherwise it does not know the spinning circle is there at all.

Common mistake

The animation stutters if you spin the element by changing width, margin or the background. Animate only rotate, transform and opacity. And remove the spinner once loading is done — an endless animation on an element hidden with opacity keeps using resources.

Functions used in this recipe

  • animation — Runs a `@keyframes` animation on an element.
  • @keyframes — Describes the steps of an animation that is then started with the `animation` property.
  • border-radius — Rounds the corners of an element.
  • transform — Moves, rotates, scales or skews an element without affecting the layout around it.

Thanks for reading!

Donate to the site — we work hard for you.