Summarize this article with:
Nobody likes staring at a blank screen. When content takes time to load, users need visual feedback that something is happening.
That’s where CSS loaders come in.
These lightweight loading animations run purely on stylesheets, no JavaScript required. They keep visitors engaged during data fetches, form submissions, and page transitions.
This collection features working CSS loaders examples you can copy directly into your projects. Spinners, progress bars, skeleton screens, dot animations, and pulse effects.
Each example includes complete code, implementation tips, and guidance on animation timing, centering techniques, and accessibility best practices.
What is a CSS Loader
A CSS loader is a visual animation that displays while content loads on a webpage.
It tells users something is happening. Data fetching, image processing, page transitions.
These loading animations use CSS keyframes, transforms, and transitions to create movement without JavaScript dependencies.
Pure CSS spinners run lighter than script-based alternatives. They don’t block the main thread.
You’ll find them on landing pages, form submissions, Ajax requests, and anywhere async operations occur.
CSS Loaders Examples To Check Out
CSS Loader Generator
A powerful CSS Loader Generator for creating custom loading animations with zero hassle.
This interactive generator lets you:
- Create 12 different loader styles from spinners to pulsing hearts
- Customize dimensions from 20px to 100px
- Adjust animation speed between 0.5x and 2x
- Pick any color to match your design
Neumorphism Gradient Vibes
See the Pen
Neumorphism Gradient Loader by samuel garcia (@sam_garcia2)
on CodePen.
The CSS Animation Show
See the Pen
CSS Animated Loader by Christofer Vilander (@c_vilander)
on CodePen.
SVG Sassiness
See the Pen
SVG ∞ loader (no JS, cross-browser, minimal code) by Ana Tudor (@thebabydino)
on CodePen.
Morning Brew Time
See the Pen
cup of coffee loader by Elena Nazarova (@nazarelen)
on CodePen.
Spiral Serenity
See the Pen
Spiral Loading by alphardex (@alphardex)
on CodePen.
Daily Dose of Beauty
See the Pen
Daily UI #20 | CSS loader by Håvard Brynjulfsen (@havardob)
on CodePen.
Get Your Game On
See the Pen
Battlenet Loader by Stix (@stix)
on CodePen.
Android Sleekness
See the Pen
Android 4.4 Kitkat Loading Screen by Simon Clavey (@simoncla)
on CodePen.
Spinning Stories
See the Pen
Loader by Alex Rutherford (@Ruddy)
on CodePen.
Liquid Dreams
See the Pen
Liquid loader by Mikael Ainalem (@ainalem)
on CodePen.
Starry Corporate Nights
See the Pen
Nutanix Loading Screen by Ken Chen (@kenchen)
on CodePen.
Burrito Magic
See the Pen
Magic Burrito by Cody Ogden (@codyogden)
on CodePen.
Chroma Spin
See the Pen
Chrome Cast Loader by Robin Brons (@bronsrobin)
on CodePen.
Cube World
See the Pen
CSS Loader by Glen Cheney (@Vestride)
on CodePen.
HexaVibes All Around
See the Pen
Hexagon Loading With CSS (2) by Osama Belal (@osama-belal)
on CodePen.
Stairway to Trust
See the Pen
CSS Stairs Loader by Irko Palenius (@ispal)
on CodePen.
Redirect with a Twist
See the Pen
Redirecting Loader by Mr Alien (@mr_alien)
on CodePen.
For the Quirkmasters
See the Pen
Weird Loader by Sikriti Dakua (@dev_loop)
on CodePen.
Cube Roller Alert
See the Pen
Loader css3 by Mathieu Richard (@MathieuRichard)
on CodePen.
Gearing Up
See the Pen
Cog loading animation by Jamie Coulter (@jcoulterdesign)
on CodePen.
Swing and Sway
See the Pen
Swing Masking Loader by Nikhil Krishnan (@nikhil8krishnan)
on CodePen.
Flipping Pancakes, Literally
See the Pen
‘Making pancake’ loader by Pawel (@pawelqcm)
on CodePen.
Bubbling Donut
See the Pen
Pure CSS bubbles float in 🍩 loader animation by Ana Tudor (@thebabydino)
on CodePen.
Poppin’ Bubbles
See the Pen
Bubble Gum Loader by ilithya (@ilithya)
on CodePen.
A Fancy Spin Party
See the Pen
Fancy CSS loaders / spinners by Jenning (@jenning)
on CodePen.
Cyclone of Simplicity
See the Pen
CSS3 Loaders by Siddharth Parmar (@Siddharth11)
on CodePen.
Dash to Load
See the Pen
CSS Dash Loader by Cassidy (@cassidoo)
on CodePen.
Chill Float Vibes
See the Pen
Floating Loading Animation by Mario Duarte (@MarioDesigns)
on CodePen.
Hashtag Breakup
See the Pen
Single element Slack loader by CrocoDillon (@CrocoDillon)
on CodePen.
That Glow Though
See the Pen
The Glowing Loader – Pure CSS Animation by Maxime Rossignol (@Maxoor)
on CodePen.
Spin to Win
See the Pen
Vivid CSS3 Spinner by Kevin Jannis (@kevinjannis)
on CodePen.
Old School Loading
See the Pen
Awesome loading screen using only HTML & CSS by Ahmad Emran (@ahmadbassamemran)
on CodePen.
Legos for Days
See the Pen
LEGO Loader by Chris Gannon (@chrisgannon)
on CodePen.
Outer Space Feels
See the Pen
Pure CSS Planet Loader Animation #cpc-planets by Rafaela Lucas (@rafaelavlucas)
on CodePen.
The Must-Have
See the Pen
Escalade Loader by Yoav Kadosh (@ykadosh)
on CodePen.
Ride the Wave
See the Pen
#4 by Sasha (@sashatran)
on CodePen.
Taste the Rainbow
See the Pen
Single Element Rainbow Pen Loader by Dario Corsi (@dariocorsi)
on CodePen.
It’s Gooey
See the Pen
gooey css loader by Shrikanth (@megatroncoder)
on CodePen.
Borderline Genius
See the Pen
CSS loader with borders by Jesgrapa (@JesGraPa)
on CodePen.
Arrows Making Waves
See the Pen
Untitled by Jules Forrest (@julesforrest)
on CodePen.
Bacon All the Way
See the Pen
Bacon Loader by Chris Gannon (@chrisgannon)
on CodePen.
Slide Into The Future

How Does a CSS Loader Work
Every loading animation CSS effect relies on three core mechanisms.
Keyframe Animations
The @keyframes rule defines animation states. You set a start point, end point, and everything between.
The browser interpolates the values automatically.
Transform Functions
Rotate, scale, translate. These properties handle the actual movement.
Transform rotate spins elements around a center point. Scale grows or shrinks them. Translate shifts position.
Animation Properties
Six properties control playback:
- animation-duration sets how long one cycle takes
- animation-timing-function controls speed curves (linear, ease, cubic-bezier)
- animation-iteration-count determines repeat behavior (infinite for loaders)
- animation-delay staggers multiple elements
- animation-direction reverses playback
- animation-fill-mode defines styles before/after execution
Combine these with border-radius for circles, opacity for fades, and box-shadow for pulse effects.
Types of CSS Loaders
Different loading states call for different visual approaches.
Spinner Loaders
The classic. A circle with a colored segment that rotates continuously.
Uses border properties with one transparent side and transform rotate animation. Most recognizable loading indicator on the web.
Progress Bar Loaders
Horizontal bars that fill from left to right. Two types exist.
Determinate bars show actual progress percentage. Indeterminate bars loop continuously when completion time is unknown.
Check out CSS progress bar examples for implementation patterns.
Skeleton Loaders
Skeleton screens show placeholder shapes matching incoming content layout.
Gray boxes pulse where text, images, and cards will appear. Reduces perceived wait time significantly.
Dot Loaders
Three or more dots with staggered bounce animation or opacity changes.
Animation-delay creates the wave effect. Simple to build, universally understood.
Pulse Loaders
Elements that grow and fade rhythmically using scale transform and opacity.
Often circles or rings. The box-shadow property adds glow effects during expansion.
Best CSS Loader Examples
Working code you can copy. Each example covers different techniques and use cases.
Simple Circle Spinner
“ .spinner { width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `
Border-radius creates the circle. One colored border segment produces the spinner effect.
Dual Ring Loader
` .dual-ring { width: 48px; height: 48px; border: 5px solid transparent; border-top-color: #3498db; border-bottom-color: #3498db; border-radius: 50%; animation: spin 1.2s linear infinite; } `
Two opposing colored segments. Feels more balanced than single-segment spinners.
Three Dot Bounce
` .dot-container { display: flex; gap: 8px; }
.dot { width: 12px; height: 12px; background: #3498db; border-radius: 50%; animation: bounce 0.6s ease-in-out infinite; }
.dot:nth-child(2) { animation-delay: 0.1s; } .dot:nth-child(3) { animation-delay: 0.2s; }
@keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-15px); } } `
Staggered delays create the wave. Adjust timing for faster or slower rhythms.
Pulse Ring
` .pulse { width: 40px; height: 40px; border: 3px solid #3498db; border-radius: 50%; animation: pulse-ring 1.5s ease-out infinite; }
@keyframes pulse-ring { 0% { transform: scale(0.5); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } } `
Scale and opacity together. Starts small and visible, expands while fading.
Gradient Spinner
` .gradient-spinner { width: 50px; height: 50px; border-radius: 50%; background: conic-gradient(from 0deg, transparent, #3498db); animation: spin 1s linear infinite; }
.gradient-spinner::before { content: ”; position: absolute; inset: 4px; background: white; border-radius: 50%; } `
Conic gradient creates smooth color transition. Inner circle masks the center.
Use the CSS Gradient Generator for custom color combinations.
Square Flip Loader
` .flip-square { width: 30px; height: 30px; background: #3498db; animation: flip 1.2s ease-in-out infinite; }
@keyframes flip { 0% { transform: perspective(120px) rotateX(0) rotateY(0); } 50% { transform: perspective(120px) rotateX(-180deg) rotateY(0); } 100% { transform: perspective(120px) rotateX(-180deg) rotateY(-180deg); } } `
D transforms with CSS perspective. Creates depth during rotation.
Bar Wave Loader
` .bar-container { display: flex; gap: 4px; align-items: center; height: 40px; }
.bar { width: 6px; background: #3498db; animation: wave 1s ease-in-out infinite; }
.bar:nth-child(1) { animation-delay: 0s; } .bar:nth-child(2) { animation-delay: 0.1s; } .bar:nth-child(3) { animation-delay: 0.2s; } .bar:nth-child(4) { animation-delay: 0.3s; } .bar:nth-child(5) { animation-delay: 0.4s; }
@keyframes wave { 0%, 100% { height: 10px; } 50% { height: 40px; } } `
Audio visualizer style. Height animation with staggered timing.
Rotating Squares
` .rotating-squares { width: 40px; height: 40px; position: relative; }
.rotating-squares::before, .rotating-squares::after { content: ”; position: absolute; width: 20px; height: 20px; background: #3498db; animation: rotate-squares 1.8s ease-in-out infinite; }
.rotating-squares::after { animation-delay: -0.9s; }
@keyframes rotate-squares { 0%, 100% { transform: rotate(0) scale(1); } 50% { transform: rotate(180deg) scale(0.5); } } `
Two pseudo-elements with offset timing. Creates interlocking rotation pattern.
How to Create a CSS Spinner Loader
Step-by-step breakdown of the most common loader type.
Step One: HTML Structure
` <div class="loader"></div> `
Single element. No nested markup needed for basic spinners.
Step Two: Base Styles
` .loader { width: 48px; height: 48px; border: 5px solid #e0e0e0; border-radius: 50%; } `
Creates a gray circle. Border-radius at 50% turns the square into a perfect circle.
Step Three: Accent Border
` .loader { border-top-color: #3498db; } `
Override one side with your brand color. This segment becomes the visible spinner.
Step Four: Animation
` .loader { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } } `
Linear timing keeps speed constant. Infinite loop runs until you hide the element.
Complete Code
` .loader { width: 48px; height: 48px; border: 5px solid #e0e0e0; border-top-color: #3498db; border-radius: 50%; animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } } `
Eight lines total. Lightweight, performant, cross-browser compatible.
For more variations, try the CSS Loader Generator tool.
How to Create a CSS Progress Bar Loader
Two approaches exist: determinate (shows actual percentage) and indeterminate (loops continuously).
Indeterminate Progress Bar
` .progress-bar { width: 200px; height: 4px; background: #e0e0e0; border-radius: 2px; overflow: hidden; }
.progress-bar::before { content: ”; display: block; width: 50%; height: 100%; background: #3498db; animation: progress 1.5s ease-in-out infinite; }
@keyframes progress { 0% { transform: translateX(-100%); } 100% { transform: translateX(300%); } } `
The pseudo-element slides across repeatedly. Overflow hidden clips it at container edges.
Determinate Progress Bar
` .progress-container { width: 200px; height: 8px; background: #e0e0e0; border-radius: 4px; }
.progress-fill { height: 100%; background: #3498db; border-radius: 4px; width: 0%; transition: width 0.3s ease; } `
Update width via JavaScript as operations complete. Transition smooths the visual change.
How to Create a CSS Skeleton Loader
Placeholder content that mimics final layout structure.
Basic Skeleton Element
` .skeleton { background: linear-gradient( deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75% ); background-size: 200% 100%; animation: shimmer 1.5s infinite; border-radius: 4px; }
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } `
Gradient animation creates the shimmer effect. Apply to any element needing a placeholder.
Skeleton Card Layout
` .skeleton-card { padding: 16px; background: white; border-radius: 8px; }
.skeleton-avatar { width: 48px; height: 48px; border-radius: 50%; }
.skeleton-title { height: 20px; width: 60%; margin: 12px 0 8px; }
.skeleton-text { height: 14px; width: 100%; margin-bottom: 8px; }
.skeleton-text:last-child { width: 80%; } `
Match dimensions to your actual content. Users perceive faster load times when layout stays stable.
CSS Loader Animation Properties
Fine-tuning these values separates amateur loaders from polished ones.
Animation Duration
Sweet spot sits between 0.8s and 1.5s for most loaders.
Too fast feels frantic. Too slow suggests system lag. Spinners work best at 1s; pulse effects at 1.5s.
Animation Timing Function
Linear keeps constant speed, ideal for rotating spinners.
Ease-in-out creates natural acceleration and deceleration for bouncing dots.
Cubic-bezier allows custom curves. Try cubic-bezier(0.68, -0.55, 0.265, 1.55) for elastic bounce.
Animation Delay
Staggers multi-element animations. Calculate intervals by dividing total duration by element count.
Five dots at 1s total: delays of 0s, 0.2s, 0.4s, 0.6s, 0.8s.
How to Center a CSS Loader
Three reliable methods depending on your layout context.
Flexbox Method
` .loader-container { display: flex; justify-content: center; align-items: center; height: 100vh; } `
Works on any container. Set height to available space.
Grid Method
` .loader-container { display: grid; place-items: center; height: 100vh; } `
Single property centers both axes. Cleaner than flexbox for this specific task.
Absolute Positioning
` .loader { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } `
Centers relative to positioned parent. Use when flex or grid isn’t available.
How to Add a CSS Loader to a Website
Implementation patterns for common scenarios.
Page Load Overlay
` <div class="page-loader"> <div class="spinner"></div> </div> `
` .page-loader { position: fixed; inset: 0; background: white; display: grid; place-items: center; z-index: 9999; transition: opacity 0.3s; }
.page-loader.hidden { opacity: 0; pointer-events: none; } `
Add hidden class when page loads via JS.
Button Loading State
` <button class="btn loading"> <span class="btn-text">Submit</span> <span class="btn-loader"></span> </button> `
` .btn { position: relative; }
.btn.loading .btn-text { visibility: hidden; }
.btn.loading .btn-loader { position: absolute; inset: 0; display: grid; place-items: center; }
.btn-loader::after { content: ”; width: 16px; height: 16px; border: 2px solid transparent; border-top-color: white; border-radius: 50%; animation: spin 0.8s linear infinite; } `
Toggle loading class during form submission. Size spinner to fit button height.
Inline Content Loader
` .content-area { min-height: 200px; position: relative; }
.content-area.loading::before { content: ”; position: absolute; inset: 0; background: rgba(255,255,255,0.8); }
.content-area.loading::after { content: ”; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 32px; height: 32px; border: 3px solid #e0e0e0; border-top-color: #3498db; border-radius: 50%; animation: spin 1s linear infinite; } `
Overlays existing content during refresh. Remove class when new data renders.
CSS Loader vs JavaScript Loader
Choose based on your specific requirements.
When CSS Wins
- Simple spinning, pulsing, or bouncing animations
- No progress tracking needed
- Performance matters (CSS runs on GPU)
- Fewer dependencies preferred
When JavaScript Wins
- Dynamic progress percentage display
- Complex sequenced animations
- Conditional animation states
- Integration with API responses
Most sites use CSS for visual animation, JS only for show/hide logic.
CSS Loader Browser Compatibility
Modern CSS animations work everywhere that matters.
Full Support
Chrome 43+, Firefox 16+, Safari 9+, Edge 12+. All current versions handle keyframes and transforms natively.
Vendor Prefixes
Still needed for older Safari versions:
` @-webkit-keyframes spin { to { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }
.loader { -webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite; } `
Use CSS Minifier tools with autoprefixer for production builds.
Fallback Strategy
Static loading text for ancient browsers:
` .loader { / Fallback / content: 'Loading...'; }
@supports (animation: spin 1s) { .loader { / Full animation / } } `
CSS Loader Accessibility
Loading states need proper communication for all users.
ARIA Attributes
` <div class="loader" role="status" aria-label="Loading content"> <span class="visually-hidden">Loading...</span> </div> `
Screen readers announce the loading state. ARIA role tells assistive tech this is a status message.
Reduced Motion
` @media (prefers-reduced-motion: reduce) { .loader { animation: none; }
.loader::after { content: ‘Loading…’; } } `
Respects user system preferences. Some users experience motion sickness or vestibular disorders.
Check web accessibility checklist guidelines for complete implementation.
Color Contrast
Loader colors need 3:1 minimum contrast ratio against backgrounds.
Test with WCAG tools. Gray spinners on white backgrounds often fail.
FAQ on CSS Loaders
What is a CSS loader?
A CSS loader is a visual animation that displays while webpage content loads. It uses keyframe animations and transform properties to create spinning, pulsing, or bouncing effects without JavaScript dependencies.
How do I create a simple CSS spinner?
Create a div with equal width and height, apply border-radius: 50% for a circle, add a colored border-top, then animate with transform: rotate(360deg) using @keyframes. Takes about eight lines of code.
What’s the best animation duration for loaders?
Most loading animations work best between 0.8 and 1.5 seconds. Spinners typically use 1 second with linear timing. Pulse effects feel natural at 1.5 seconds with ease-in-out timing function.
How do I center a CSS loader on the page?
Use display: grid with place-items: center on the container, or display: flex with justify-content and align-items set to center. Set container height to 100vh for full viewport coverage.
Can CSS loaders work without JavaScript?
Yes. Pure CSS spinners and animations run entirely on stylesheets using @keyframes, transforms, and animation properties. JavaScript is only needed to show or hide the loader element.
What’s the difference between spinner and skeleton loaders?
Spinners are animated icons indicating activity. Skeleton loaders display placeholder shapes matching the incoming content layout, reducing perceived wait time by showing where elements will appear.
How do I make a loader accessible?
Add role=”status” and aria-label=”Loading” to the loader element. Include visually hidden text for screen readers. Respect prefers-reduced-motion media query for users with vestibular disorders.
Why is my CSS loader not spinning smoothly?
Check your animation-timing-function. Use linear for constant rotation speed. Avoid animating properties that trigger layout recalculation. Stick to transform and opacity for GPU-accelerated, smooth performance.
How do I add a loader to a button?
Position a small spinner inside the button using absolute positioning. Toggle a loading class that hides button text and displays the spinner. Size the animated spinner to fit button height.
Do CSS loaders affect page performance?
Minimal impact. CSS animations using transform and opacity run on the GPU, avoiding main thread blocking. They’re lighter than JavaScript-based alternatives and don’t increase bundle size significantly.
Conclusion
These CSS loaders examples give you ready-to-use code for any loading scenario. Copy them directly into your stylesheets.
Pure CSS animation keeps things lightweight. No external libraries, no JavaScript overhead, just clean keyframe-based motion that runs on the GPU.
Pick the right loader type for your context. Spinners work for quick operations. Progress bars suit file uploads. Skeleton screens reduce perceived wait time on content-heavy pages.
Don’t forget accessibility. Add ARIA labels, respect reduced motion preferences, and maintain proper contrast ratios.
Test your loading animations across browsers. Modern CSS transform and animation properties enjoy wide support, but vendor prefixes still help older Safari versions.
Start simple. A basic circular spinner takes eight lines of code and solves most use cases.

