A CSS spinner signals "we're working on it" during the 200ms-3s gap between a click and a result — the visual difference between a snappy app and one that feels broken. These 25 hand-coded spinners cover every production loading-indicator pattern developers reach for: neon arc, dual counter-rotate rings, dot chase orbit, gradient conic sweep, heartbeat pulse, equalizer wave bars, stacked ring helix, morph square-to-circle, comet trail, DNA double helix, folding cube grid, ripple pulse ring, clock tick sweep, infinity loop stroke, bouncing elastic dots, spiral galaxy, glassmorphism, cyberpunk segmented ring, breathing circle, particle scatter burst, retro TV static, liquid blob, progress arc fill, matrix rain column, and aurora orb. All 100% pure CSS — zero JavaScript, zero library dependencies (no react-spinners, no SpinKit, no loading.io snippet). Every spinner respects prefers-reduced-motion, uses scoped .sp-NN__* class names so multiple spinners coexist without style bleed, ships with proper role="status" + aria-live markup for screen reader accessibility, MIT-licensed.

25 pure CSSPublished

Related20 CSS Rotate Animations20 CSS Loaders20 CSS Loading Animations22 CSS Skeleton Loaders

Neon Arc CSS Spinner — preview
01 / 25Pure CSS

Neon Arc CSS Spinner

A single glowing cyan arc rotates on a deep-dark background, with a luminous leading-edge dot that amplifies the neon effect via CSS drop-shadow filters.

Published

Dual Counter-Rotate Ring Spinner — preview
02 / 25Pure CSS

Dual Counter-Rotate Ring Spinner

Two concentric rings spin in opposite directions — outer purple and inner pink — with a pulsing radial core, creating a hypnotic, gyroscopic loading indicator.

Published

Dot Chase Orbit Spinner — preview
03 / 25Pure CSS

Dot Chase Orbit Spinner

Four multi-coloured dots orbit a shared centre, each fading in and out with staggered delays to create a chasing, comet-like orbital trail effect.

Published

Gradient Conic Sweep Spinner — preview
04 / 25Pure CSS

Gradient Conic Sweep Spinner

A conic-gradient disk sweeps through deep violet-to-cyan colours with a transparent cutout tail, creating a smooth colour-wheel spinner with a bright leading-edge tip.

Published

Heartbeat Pulse Loader — preview
05 / 25Pure CSS

Heartbeat Pulse Loader

A vivid red core pulses with a cardiac double-beat rhythm while three concentric ripple rings expand outward and fade, mimicking a real heartbeat waveform.

Published

Wave Bar Equalizer Spinner — preview
06 / 25Pure CSS

Wave Bar Equalizer Spinner

Seven vertical bars oscillate like an audio level meter, scaling from a flat line to full height in a symmetric wave pattern using staggered CSS animation delays.

Published

Stacked Ring Helix Spinner — preview
07 / 25Pure CSS

Stacked Ring Helix Spinner

Three concentric rings in blue, indigo, and violet spin at alternating speeds and directions, with each ring using different border-side pairs to create a three-axis helix illusion.

Published

Morph Square-to-Circle Spinner — preview
08 / 25Pure CSS

Morph Square-to-Circle Spinner

A hollow square morphs fluidly through four asymmetric border-radius stages into a perfect circle and back, while simultaneously rotating — a classic CSS shape-morphing technique.

Published

Comet Trail CSS Spinner — preview
09 / 25Pure CSS

Comet Trail CSS Spinner

A conic-gradient comet with a long fading purple tail sweeps around a dark ring, with a bright glowing tip dot that precisely tracks the leading edge of the arc.

Published

DNA Double Helix Spinner — preview
10 / 25Pure CSS

DNA Double Helix Spinner

Eight nucleotide pairs animate as two interweaving dot chains — one cyan, one pink — translating horizontally in opposing directions to simulate a rotating DNA double helix.

Published

Folding Cube Grid Spinner — preview
11 / 25Pure CSS

Folding Cube Grid Spinner

A 3×3 grid of teal cubes each flip through two 90° rotation axes in sequence with staggered delays, creating a cascading wave of 3D folding tiles.

Published

Ripple Pulse Ring Spinner — preview
12 / 25Pure CSS

Ripple Pulse Ring Spinner

Four concentric rings expand outward from a solid azure dot in sequence, each fading from full opacity to invisible as it reaches its maximum radius — like rings in water.

Published

Clock Tick Sweep Spinner — preview
13 / 25Pure CSS

Clock Tick Sweep Spinner

A precise gold second-hand sweeps in discrete tick steps around a minimal dark clock face with 12 hour markers, using CSS steps() timing to simulate mechanical tick motion.

Published

Infinity Loop Stroke Spinner — preview
14 / 25Pure CSS

Infinity Loop Stroke Spinner

An SVG infinity symbol (∞) animates its stroke drawing from start to end and back using stroke-dasharray and stroke-dashoffset, with a glowing lime-green line on a dark field.

Published

Bouncing Elastic Dots Spinner — preview
15 / 25Pure CSS

Bouncing Elastic Dots Spinner

Three coloured dots bounce with spring-like squash and stretch physics — compressing horizontally and elongating vertically at peak height — using a multi-step cubic-bezier keyframe.

Published

Spiral Galaxy CSS Spinner — preview
16 / 25Pure CSS

Spiral Galaxy CSS Spinner

Three overlapping conic-gradient arms spiral outward from a bright central core, blurred and rotated 120° apart to simulate a three-armed barred spiral galaxy.

Published

Glassmorphism Loader Spinner — preview
17 / 25Pure CSS

Glassmorphism Loader Spinner

A frosted-glass circle with backdrop-filter blur floats over animated colour blobs, with two nested arcs spinning at different speeds to create a layered glassmorphic loading indicator.

Published

Cyberpunk Segmented Ring Spinner — preview
18 / 25Pure CSS

Cyberpunk Segmented Ring Spinner

A yellow dashed outer ring and a magenta inner arc spin in opposite directions around a rotating wireframe diamond core, channelling the segmented HUD aesthetics of cyberpunk UIs.

Published

Breathing Circle Loader — preview
19 / 25Pure CSS

Breathing Circle Loader

A calm azure orb slowly inhales and exhales with a scale pulse while three expanding rings propagate outward in a continuous ripple, creating a meditative loading state.

Published

Particle Scatter Burst Spinner — preview
20 / 25Pure CSS

Particle Scatter Burst Spinner

Eight coloured particles radiate outward from a central white core, fading and shrinking to nothing at the edge of their orbit while the whole assembly rotates slowly.

Published

Retro TV Static Noise Loader — preview
21 / 25Pure CSS

Retro TV Static Noise Loader

A miniature CRT television screen filled with flickering monochrome pixel tiles simulates analog static noise, complete with scanline overlay and vignette darkening.

Published

Liquid Blob CSS Spinner — preview
22 / 25Pure CSS

Liquid Blob CSS Spinner

A fluid-blue gradient blob morphs organically through six distinct multi-value border-radius shapes while slowly rotating, creating an amorphous liquid motion effect.

Published

Progress Arc Fill Spinner — preview
23 / 25Pure CSS

Progress Arc Fill Spinner

An SVG circle arc fills from empty to complete on a two-second loop, with a 100% percentage counter label centred inside — suitable as both a loading indicator and a determinate progress ring.

Published

Matrix Rain Column Spinner — preview
24 / 25Pure CSS

Matrix Rain Column Spinner

Five columns of katakana characters and binary digits cascade downward with a bright white leading character fading to dark green, evoking the iconic Matrix digital rain effect.

Published

Aurora Gradient Orb Spinner — preview
25 / 25Pure CSS

Aurora Gradient Orb Spinner

A softly glowing orb pulses with shifting aurora borealis colours — layered radial gradients rotate independently with hue-shift filters — while a single orbital ring traces a luminous dot around the perimeter.

Published

FAQ

Frequently asked questions

What's the difference between a CSS spinner and a CSS loader?
Common-usage overlap, but the canonical distinction: A spinner is one specific pattern of loader — typically a rotating ring, arc, or dot that signals "indeterminate work in progress." Spinners are a SUBSET of loaders. Loaders also include skeleton screens (Facebook/LinkedIn content placeholders), progress bars (file uploads), bouncing-balls dots, typing indicators, and shimmer effects. Use a SPINNER when: (1) the operation is indeterminate (you don't know how long it'll take) AND (2) you don't have layout info to preview (no skeleton possible) — generic API calls, OAuth redirects, search-as-you-type, form submissions. Use a SKELETON instead when: you DO know the eventual content shape (article cards, feed posts, dashboard tiles) — skeleton screens reduce perceived wait time by ~22% per Nielsen Norman Group research vs spinners. Use a PROGRESS BAR when: you know the percentage complete (file uploads, video processing). The 25 demos in this collection are all spinners — rotating, pulsing, or rhythmic indicators for indeterminate operations. For broader patterns including skeletons + progress bars, see the CSS Loaders collection.
Should I use react-spinners / SpinKit / loading.io, or build with pure CSS?
Depends on your stack and bundle budget. If you're on React: react-spinners ships ~30 spinners as ~8kb gzipped. Excellent DX (just import and use), no CSS to write. Bundle penalty: 8kb for one component. react-loading-icons ships SVG icons at ~5kb. If you're on any vanilla stack (Astro, Vue, Svelte, Rails, WordPress, plain HTML) — the React-specific options force you to bring React into your bundle. SpinKit (Tobias Ahlin's CSS-only library, free): ~3kb of CSS for ~10 spinners. The classic option. Drawback: the designs feel dated (~2015 aesthetic). loaders.css: ~6kb of CSS for ~50 spinners. epic-spinners: Vue-specific, ~10kb. loading.io: web generator. Free tier watermarks output; pay $99/year to remove. css.gg: ~700 CSS icons including 10 spinners, ~10kb min. This collection's 25 spinners: 0 bytes of JavaScript, ~0.5-2kb of CSS per demo (only the ones you use), framework-neutral, MIT-licensed, modify-and-resell allowed. Best fit when: you want a SPECIFIC aesthetic (cyberpunk, glassmorphism, audio-bars, matrix), you don't want to pay loading.io's subscription, you want copy-paste-and-modify code instead of a library API, or you're optimizing bundle size on a hot path.
How do I add a leading-edge dot to a spinner that tracks the arc tip?
Demos 01 (Neon Arc), 04 (Conic Sweep), 09 (Comet Trail) all ship this pattern. The mechanic: (1) Put the arc/conic AND the dot inside a single rotating container. Both children share the parent's @keyframes spin animation by inheritance, so they rotate in perfect sync — the dot stays locked to the arc tip throughout the rotation. (2) Position the dot at the 12 o'clock position of the unrotated container via position: absolute; top: 0; left: 50%; transform: translate(-50%, -50%) — this centers the dot exactly on the arc midline at the top of the spinner. (3) Size the dot to match (or slightly exceed) the arc stroke thickness so it reads as a smooth rounded cap, not a notch. For a 4px-thick arc, a 4px dot creates a clean continuation; a 10px dot creates a glowing "head" effect for the comet/leading-edge look. Three production-grade details most spinner tutorials get wrong: (a) Use transform: translate(-50%, -50%) not margin hacks — translate is GPU-accelerated and won't trigger layout. (b) Apply the box-shadow glow on the DOT itself, not on the parent — the glow needs to rotate with the dot. (c) Use filter: drop-shadow on the arc instead of box-shadow — drop-shadow follows the actual arc shape (transparent borders pass through), while box-shadow applies to the bounding box.
How do I implement the conic-gradient comet trail effect?
Demo 09 (Comet Trail) ships this. The pattern: (1) Use conic-gradient with 4-5 stops that fade from full color at 0° (the bright comet head) through decreasing opacity to transparent. Example: conic-gradient(var(--c) 0deg, rgba(c,0.4) 60deg, rgba(c,0.15) 120deg, transparent 180deg, transparent 360deg) — bright tip at 12 o'clock, fading tail wrapping clockwise through 180°, then a transparent gap from 180-360°. (2) Create the donut hole by layering an absolutely-positioned child div with the same background color as the page, inset:10px (half the desired ring thickness). The conic disc shows through only at the ring area. (3) Rotate the entire container via @keyframes spin { to { transform: rotate(360deg) } } with linear timing — the comet appears to sweep continuously around. Three production caveats: (a) conic-gradient needs Chrome 69+, Safari 12.1+, Firefox 83+ — universal as of 2022 but always provide a border-based fallback for legacy support. (b) The donut-hole technique breaks over images or page backgrounds with non-solid colors — use mask-image: radial-gradient(transparent 50%, black 51%) instead for composable contexts. (c) GPU layer promotion — stacking 20+ conic spinners on one page can saturate the compositor on low-end Android. For high-frequency repeat usage, limit to ~3-5 concurrent.
How do I make a spinner accessible for screen reader users?
Five accessibility considerations matter for spinners, and all 25 demos in this collection address them. (1) role="status" on the spinner's outer wrapper. Tells assistive tech (NVDA, JAWS, VoiceOver, TalkBack) that the element conveys status information. Screen readers announce its content politely without interrupting the user. (2) aria-live="polite" in addition to role="status" (the role implies it but explicit is more compatible). Polite = announce when the user is idle. Avoid aria-live="assertive" for spinners — assertive interrupts the user, which is jarring for routine loading announcements. (3) Visually-hidden text inside the spinner: <span class="sr-only">Loading…</span>. The visible rotation means nothing to a blind user — the hidden "Loading…" text IS the announcement. (4) Update the text when state changes. When loading completes, swap the inner text to "Loaded" or remove the spinner from the DOM. The aria-live region announces the change. (5) prefers-reduced-motion: reduce — for vestibular-sensitive users (people who experience motion sickness from continuous spinning), pause or simplify the animation. Don't just remove it (then there's no loading indication) — replace with a static "Loading…" text or a single-frame icon. Common mistake most online spinner tutorials make: animating the visual with CSS but providing ZERO aria/role markup. Blind users have no idea your app is loading. The 25 demos here ship the markup correctly out of the box.
Which CSS animation property is best for spinner performance?
The golden rule: animate transform and opacity only. Both are GPU-accelerated on the compositor thread — they DON'T trigger layout recalculation or paint, so they DON'T affect INP (Interaction to Next Paint), the Core Web Vital that replaced FID in March 2024. Every spinner in this collection follows this rule — rotation uses transform: rotate(360deg), scaling uses transform: scale(...), fading uses opacity. Five spinner-specific gotchas: (a) Don't animate border-color on a loop — paint-only, but on every frame across the whole element. Cheap individually, but stacking 5+ such spinners drops FPS on mobile. (b) Don't animate box-shadow on a loop — paint + blur recalculation every frame. Catastrophic on low-end devices. Use filter: drop-shadow for shadow + animate opacity on a sibling glow overlay instead. (c) conic-gradient with animated stop positions is paint-expensive — rotate the entire conic element via transform instead. (d) backdrop-filter on glassmorphism spinners over a long page kills scroll FPS — apply only when needed, not on a 100vh sticky element. (e) Off-screen spinners shouldn't animate — use IntersectionObserver to add animation-play-state: paused when out of view. Saves battery + CPU. All 25 demos in this collection: 95+ Lighthouse Performance score on Pixel 5 baseline.
How is a CSS spinner different from a CSS loader vs a CSS preloader?
Three terms with overlapping but distinct meanings: (1) CSS spinner — a small, looping rotating/pulsing indicator placed INLINE within UI to show that a SPECIFIC OPERATION is in progress. Examples: spinner inside a submit button during form post, spinner replacing a chart while data loads, spinner in a profile card while avatar uploads. Typically 24-80px in size. The 25 demos in this collection are spinners. (2) CSS loader — broader term covering any loading-state UI element including spinners, skeleton screens, progress bars, typing dots, shimmer effects. A spinner is one TYPE of loader. The CSS Loaders collection covers all loader types. (3) CSS preloader — full-page overlay shown BEFORE the application is ready to interact, typically during initial page load while critical assets are still downloading. Usually a full-viewport (100vw × 100vh) cover with a centered logo + spinner that fades out via JS once window.load fires. Spinners are often USED within preloaders as the rotating element. Some teams use "preloader" specifically for initial-load full-screen UIs and "spinner" for inline UI. Most teams use the terms interchangeably.
What's the right spinner size for buttons, cards, and full-page loaders?
Sizing varies by context. Buttons (inline next to button text): 14-16px square. Match the line-height of the button text so it sits on the baseline. The spinner replaces a button's icon or sits to the left of the label during loading. Typical loading state: <button disabled> <Spinner size=14 /> Saving… </button>. Card-level (replacing a chart, image, or content block): 32-48px square, centered in the placeholder space. Should be small enough that it doesn't visually dominate the card but big enough to be perceived as an intentional element (not a glitch). Inline within forms or tables: 16-24px square. Same scale as text. Modal / dialog (full-screen blocking): 48-72px. The user is staring directly at this — bigger reads as more deliberate. Often paired with text "Processing your request…" below. Full-page preloader: 64-96px, centered on the viewport. Optionally accompanied by a brand logo above the spinner. Floating action / overlay (loading on top of content): 40-56px with a subtle backdrop blur or scrim. All 25 demos in this collection default to a wrapper-sized spinner (sized via a CSS custom property like --size: 80px) — change one value to rescale for any context. Most demos use 40-80px ranges out of the box.
Will spinner animations on a long page hurt my scroll performance?
Yes if you have many spinners off-screen, no if you only have one visible. The reason: CSS animations on transform/opacity are GPU-accelerated and cheap per spinner — but every additional animated element occupies a GPU compositor layer, and there's a hard limit on how many layers the browser can handle smoothly. On a desktop with a fast GPU, 50+ concurrent spinner animations are fine. On low-end Android, 10+ concurrent can drop scroll FPS to 30-40 (visible jank). Three strategies for pages that show many spinners (e.g., a dashboard with 20 cards all loading their data): (1) IntersectionObserver pause — when a spinner scrolls out of view, set animation-play-state: paused; when it scrolls back in, set running. The visible spinners animate; off-screen ones don't burn battery. ~15 lines of JS. (2) content-visibility: auto (Chrome 85+, Safari 18+, Firefox 125+) on each card. The browser automatically skips rendering off-screen cards, including their spinners. Zero JS. The future-proof approach for any long page. (3) Replace with a single global spinner — instead of 20 cards each with a spinner, show ONE "loading dashboard…" spinner at the top of the page and reveal cards as they finish loading. Simpler UX, fewer animations. This collection's spinners all use transform + opacity (GPU-friendly) and respect prefers-reduced-motion. INP impact: negligible per individual spinner. Lighthouse mobile-profile: 95+ Performance on Pixel 5 baseline with up to 5 concurrent spinners visible.
Which spinner should I use for my project?
Quick decision guide for all 25 demos. Generic API call / form submit (200ms-3s): Demo 01 (Neon Arc) for tech/modern brand; Demo 03 (Dot Chase Orbit) for Material Design; Demo 04 (Gradient Conic Sweep) for premium / colorful brand. iOS / iPad-feeling app: Demo 02 (Dual Counter-Rotate Ring) matches the iOS UIActivityIndicator aesthetic. SaaS dashboard with multiple concurrent operations: Demo 19 (Breathing Circle) — slow, calming, doesn't dominate the viewport when many run simultaneously. E-commerce / checkout / payment processing: Demo 13 (Clock Tick Sweep) — communicates "time-bound operation" subtly. Search-as-you-type / autocomplete: Demo 15 (Bouncing Elastic Dots) or Demo 03 (Dot Chase) — small, low-visual-weight, reads as "thinking." Music / audio / media app: Demo 06 (Wave Bar Equalizer) — the audio-visualizer pattern, brand-aligned for music products. Scientific / biotech / data product: Demo 10 (DNA Double Helix) — visually communicates "processing biological data." Astronomy / space / planetary app: Demo 16 (Spiral Galaxy) — orbital pattern. Medical / wellness / health app: Demo 05 (Heartbeat Pulse) — domain-aligned. 3D-forward / WebGL adjacent brand: Demo 07 (Stacked Ring Helix), Demo 11 (Folding Cube Grid). Premium / design-forward brand: Demo 17 (Glassmorphism Loader) for frosted aesthetic; Demo 25 (Aurora Orb) for atmospheric. Gaming / Web3 / esports / cyberpunk brand: Demo 18 (Cyberpunk Segmented Ring), Demo 24 (Matrix Rain Column). Comet / shooting-star aesthetic: Demo 09 (Comet Trail). Ripple-based (concentric expansion): Demo 12 (Ripple Pulse Ring). Determinate progress (% complete known): Demo 23 (Progress Arc Fill) — the only determinate spinner in the set. Playful / branded / celebration moment: Demo 20 (Particle Scatter Burst) — when loading should feel exciting. Minimal / abstract / art-direction: Demo 08 (Morph Square-to-Circle), Demo 14 (Infinity Loop), Demo 22 (Liquid Blob). Retro / nostalgic brand: Demo 21 (Retro TV Static Noise). All 25 demos: 100% Pure CSS, role="status" + aria-live="polite" + visually-hidden "Loading…" text out of the box, prefers-reduced-motion respected, MIT-licensed.

Related collections

20 CSS Animated Buttons preview

20 CSS Animated Buttons

20 hand-coded CSS animated buttons — neon glow, ripple, 3D press, liquid fill, jelly bounce, shine sweep, animated border, moving gradient CTA, text flip, submit success state, add-to-cart progress, download icon, hamburger-to-close, toggle switch, loading spinner inside button, next/prev arrow nav, and ghost button background reveal. Half pure CSS, half lightweight JS for production interactions.

11 CSS animation-timeline Demos preview

11 CSS animation-timeline Demos

11 pure CSS animation-timeline demos built on the W3C scroll() and view() spec — reading progress bar, view-timeline fade & reveal, shrinking sticky header, stacking cards, horizontal scroll section, parallax hero, container shadow indicators, reverse-scroll columns, text scrim reveal, cover card to sticky header, and image zoom / clip-path wipe. Zero JS, off the main thread, Core Web Vitals safe. Copy-paste ready.

25 CSS Background Animations preview

25 CSS Background Animations

25 hand-coded CSS background animations for SaaS hero sections, developer tool documentation, agency portfolios, gaming and Web3 landing pages, seasonal e-commerce campaigns, and dark-mode dashboards. Covers full-screen gradient shifts, animated mesh gradients, aurora borealis glow, cursor spotlight follow, interactive water ripples, dot grid and diagonal stripe patterns, SVG grain and noise texture overlays, topographic contour lines, layered SVG waves, plasma and lava lamp fluids, bokeh light blur, particle constellation networks, matrix digital rain, synthwave 3D perspective grids, starfield warp speed, CRT scanline overlays, fog and mist drift, morphing organic blobs, floating glassmorphism orbs, halftone dot patterns, starry night skies, floating geometric shapes, rising bubbles, and falling snow. 20 are pure CSS with zero JavaScript; the 5 that need it use vanilla canvas or pointer tracking with no dependencies. Every background animates compositor-only properties so it never blocks the main thread, is scoped under a .bga-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

Search CodeFronts

Loading…