TaskBuild a spinner. @keyframes spin { to { transform: rotate(360deg); } }. .spinner { width: 32px; height: 32px; border: 3px solid #e5e7eb; border-top-color: #3B82F6; border-radius: 50%; animation: spin 0.8s linear infinite; }. Center it on the page.
Loading spinners and skeletons
75 XP6 min
Theory
Two loading patterns
1. Spinner (indeterminate)
@keyframes spin { to { transform: rotate(360deg); } }
.spinner {
width: 24px; height: 24px;
border: 3px solid #e5e7eb;
border-top-color: #3B82F6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}Border trick: full ring + colored "highlight" arc on top. Spinning makes it appear to chase itself.
2. Skeleton (placeholder)
@keyframes shimmer {
0% { background-position: -200px 0; }
100% { background-position: calc(200px + 100%) 0; }
}
.skeleton {
height: 16px; width: 70%;
background: linear-gradient(90deg, #f3f4f6 0%, #e5e7eb 50%, #f3f4f6 100%);
background-size: 200px 100%;
background-repeat: no-repeat;
animation: shimmer 1.5s ease-in-out infinite;
border-radius: 4px;
}Gradient with a moving highlight band. Used in place of actual content while data loads.
When to use which
- Spinner β when load time is short (<1s expected). Tells user "wait a moment."
- Skeleton β when load time is longer (1-3s expected) OR layout is complex (lists, cards, dashboards). Maintains layout integrity β no jump when content arrives.
- Progress bar β when you know the percentage. Always preferred over spinner if measurable.
Don't show spinners for <100ms
Spinners that flash for 50ms and disappear are jarring. Wait at least 150ms before showing a spinner.
π
Sign up to start coding
Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial β card required, cancel anytime.
Sign up β free trial βFirst 10 lessons in each track are free. No card needed for those.