No GIFs, no libraries. Five production-ready loaders.
1. The classic ring
.spinner {
width: 36px; aspect-ratio: 1;
border: 4px solid rgba(255,255,255,.15);
border-top-color: #6d6ffb;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }2. Three bouncing dots
.dots { display: flex; gap: 6px; }
.dots span {
width: 10px; aspect-ratio: 1; border-radius: 50%;
background: #6d6ffb;
animation: bounce 0.6s infinite alternate;
}
.dots span:nth-child(2) { animation-delay: 0.2s; }
.dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes bounce { to { translate: 0 -8px; opacity: .5; } }3. Pulse · 4. Bar · 5. Conic ring
.pulse { animation: pulse 1.2s ease infinite; }
@keyframes pulse { 50% { transform: scale(1.15); opacity: .5; } }
.bar::after { content: ""; display: block; height: 3px; width: 30%;
background: #6d6ffb; animation: slide 1s ease-in-out infinite alternate; }
@keyframes slide { to { translate: 230% 0; } }
.ring { background: conic-gradient(#6d6ffb var(--p, 70%), #333 0);
border-radius: 50%; mask: radial-gradient(farthest-side, transparent 70%, #000 71%); }Wrap them all: @media (prefers-reduced-motion: reduce) { .spinner { animation: none } }.