ProgramGuru

CSS Loading Spinners and Progress Bars

CSS Loading Spinners and Progress Bars

A loading indicator signals unknown-duration work, while a progress indicator displays a known percentage or amount.

What you’ll learn

  • Create a decorative CSS spinner.
  • Use a real progress element for measurable completion.
  • Respect reduced-motion settings.

Understand the concept

A CSS border spinner can be made with border-radius:50%, one contrasting border side, and a rotation animation. Give it a text label and reduce animation for users who request less motion.

For real task completion, prefer the native <progress value="..." max="..."> element. Its semantics communicate progress to assistive technologies; CSS only changes the appearance.

What the browser evaluates

Rotation changes only the painted spinner; the progress element represents a numerical completion fraction.

CSS loading spinner

Use one bright border edge and animate rotation.

HTML

<div class="load-row"><span class="spinner" aria-hidden="true"></span><span>Loading results…</span></div>

CSS

@keyframes pgcss-loading-spin { to { transform: rotate(360deg); } } .load-row { display: flex; gap: 12px; align-items: center; padding: 10px; } .spinner { width: 22px; height: 22px; border: 3px solid #bfdbfe; border-top-color: #1d4ed8; border-radius: 50%; animation: pgcss-loading-spin .9s linear infinite; } @media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }

Rendered output

Loading results…

Observe: The circular indicator rotates while the readable status label remains steady.

Measured progress

Show a real 70% completion value.

HTML

<div class="progress-demo"><label for="upload-progress">Uploading files — 70%</label><progress id="upload-progress" max="100" value="70">70%</progress></div>

CSS

.progress-demo { display: grid; gap: 9px; max-width: 330px; font-family: Arial, sans-serif; } .progress-demo progress { width: 100%; height: 15px; accent-color: #0f766e; }

Rendered output

70%

Observe: The native progress control encodes the numeric 70/100 value as well as displaying a bar.

Explain the result

Rotation changes only the painted spinner; the progress element represents a numerical completion fraction.

Compare the two examples: identify the selector, each changed property, and which visible part of the output proves that the CSS took effect.

Common mistakes to avoid

  • A spinner cannot tell the user how much time remains.

  • Avoid animations that cannot be stopped or reduced when they are nonessential.

Try it yourself

Change the progress value to 35 and modify the visible label to match.

Before changing the code, predict what will change. Then verify by checking the rendered result.

Check your understanding

Which HTML element semantically represents 70% completed work?
Choose one answer. You can try again.

Answer and explanation

progress

The progress element exposes value and maximum semantics.

What you should remember

Use spinners for indeterminate waits and native progress for measured completion.

Revisit the rendered examples if the rule still feels abstract. Change one declaration at a time so you can connect cause and effect.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: CSS Pricing Table Examples →