A loading spinner that respects your visitors

Build a spinner, and provide a static alternative.

What to build

A keyframe animation with a reduced motion fallback.

Requirements

  • A @keyframes rule called spin that rotates from 0deg to 360deg.
  • .spinner is 32px by 32px, with border-radius: 50%, a 4px solid lightgray border, and a border-top-color of teal.
  • .spinner plays spin over 1s, linear, forever.
  • Under prefers-reduced-motion: reduce, .spinner has animation: none.

Constraints

Do not use any images.

Example

The second code block in the lesson shows @keyframes.

Why it works

A coloured top border on a round box looks like a moving arc when rotated, and the query ensures that those who asked for less motion are not shown it.

Hints

Hint 1

A spinner rotates from 0 to 360 degrees.

Hint 2

animation is shorthand for name, duration, timing and count.

Hint 3

Turn it off inside the reduced motion query.

Solution

Show one correct solution (try it yourself first)
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Spinner</title>
  <style>
    @keyframes spin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .spinner {
      width: 32px;
      height: 32px;
      border-radius: 50%;
      border: 4px solid lightgray;
      border-top-color: teal;
      animation: spin 1s linear infinite;
    }
    @media (prefers-reduced-motion: reduce) {
      .spinner { animation: none; }
    }
  </style>
</head>
<body>
  <div class="spinner" role="status" aria-label="Loading"></div>
</body>
</html>

Lesson: Transitions, transforms and animations →