Je winkelwagen is leeg
Producten die je toevoegt, verschijnen hier.
Met de juiste animatie geef je gebruikers het gevoel dat er iets gebeurt, wat de ervaren wachttijd met wel 30% kan verkorten.
Wist je dit? Gebruikers wachten gemiddeld slechts 2 seconden voordat ze de pagina verlaten. Hoe houd je bezoekers betrokken terwijl je content laadt?
De oplossing is visuele feedback via loading animaties. Met de juiste animatie geef je gebruikers het gevoel dat er iets gebeurt. Dit verkort de ervaren wachttijd met wel 30%.
In dit artikel ontdek je 20 praktische loading animaties met complete code voorbeelden. We starten met 7 custom animaties die speciaal ontwikkeld zijn voor optimale performance. Daarna volgen 13 extra voorbeelden georganiseerd per categorie.
Elke animatie komt met een live CodePen demo waar je direct mee kunt experimenteren. Klaar om je website levendiger te maken?
TL;DR — Welke loading animatie gebruik je wanneer?
Scroll naar beneden voor 20 werkende CodePen voorbeelden met copy-paste code.
Definitie: Een loading animatie is een visuele indicator die gebruikers laat zien dat een website of applicatie bezig is met het laden van content. Dit kan een spinner, skeleton screen, progress bar of andere animatie zijn die feedback geeft tijdens wachttijd.
We gaan de animaties bekijken, maar ook de technische principes erachter. Je leert waarom bepaalde CSS
KeurigOnline zegtCSSCSS is de stijltaal waarmee je de visuele opmaak en layout van HTML-pagina’s bepaalt. properties beter zijn voor performance en hoe je JavaScript
KeurigOnline zegtJavaScriptJavaScript is de browser- en server-scriptingtaal voor interactieve, asynchrone webapplicaties. gebruikt om animaties dynamisch te starten en stoppen.
We beginnen met 7 custom voorbeelden. Daarna volgen 13 gecategoriseerde varianten.
🎯 Loading animatie implementeren in 4 stappen
Een elegante pulserende cirkel die gebruikmaakt van CSS animations en radial gradients. Perfect voor moderne interfaces en subtiele feedback tijdens AJAX requests.
<div class="loader-container">
<div class="pulse-loader"></div>
</div>
.loader-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #1a1a2e;
}
.pulse-loader {
width: 80px;
height: 80px;
background: radial-gradient(circle, #667eea 0%, #764ba2 100%);
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
box-shadow: 0 0 40px rgba(102, 126, 234, 0.6);
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.3);
opacity: 0.7;
}
}
Deze animatie gebruikt de volgende CSS technieken:
@keyframes pulse: Definieert de pulserende beweging met transform en opacityradial-gradient: Creëert een mooie kleurovergang van binnen naar buitentransform: scale(): Hardware-accelerated transformatie voor soepele animatieanimation timing: 1.5s ease-in-out zorgt voor natuurlijke bewegingbox-shadow: Gloed-effect dat mee pulseertPerformance tip: transform en opacity zijn GPU-accelerated properties, waardoor deze animatie 60fps haalt op alle moderne browsers.
De bekende "typing indicator" animatie die je kent van chat apps. Drie dots die elkaar opvolgen met een subtiel bounce effect.
<div class="typing-loader">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #0f0f23;
}
.typing-loader {
display: flex;
gap: 8px;
}
.dot {
width: 12px;
height: 12px;
background: #00d9ff;
border-radius: 50%;
animation: bounce 1.4s infinite ease-in-out;
}
.dot:nth-child(1) {
animation-delay: 0s;
}
.dot:nth-child(2) {
animation-delay: 0.2s;
}
.dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes bounce {
0%, 80%, 100% {
transform: translateY(0) scale(1);
opacity: 1;
}
40% {
transform: translateY(-20px) scale(1.1);
opacity: 0.8;
}
}
Technische details:
animation-delay: Elke dot krijgt 0.2s vertraging voor het staggered effectnth-child selector: Targeting van specifieke dots zonder extra classestranslateY: Verticale bounce beweging (GPU-accelerated)scale(1.1): Subtiele groei op het hoogste puntgap property: Moderne CSS voor spacing zonder marginsEen progress indicator die visueel toont hoeveel procent is geladen. Combineert SVG stroke-dashoffset met JavaScript voor real-time updates.
<div class="progress-container">
<svg class="progress-ring" width="120" height="120">
<circle class="progress-ring-bg" cx="60" cy="60" r="52"></circle>
<circle class="progress-ring-circle" cx="60" cy="60" r="52"></circle>
</svg>
<div class="progress-text"><span id="percentage">0</span>%</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #1e1e2e;
font-family: 'Inter', sans-serif;
}
.progress-container {
position: relative;
}
.progress-ring {
transform: rotate(-90deg);
}
.progress-ring-bg {
fill: none;
stroke: #2d2d44;
stroke-width: 8;
}
.progress-ring-circle {
fill: none;
stroke: #00ff88;
stroke-width: 8;
stroke-linecap: round;
stroke-dasharray: 326.73;
stroke-dashoffset: 326.73;
transition: stroke-dashoffset 0.3s ease;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
font-weight: 700;
color: #00ff88;
}
const circle = document.querySelector('.progress-ring-circle');
const percentageEl = document.getElementById('percentage');
const radius = 52;
const circumference = 2 * Math.PI * radius;
let progress = 0;
function updateProgress() {
progress += 1;
if (progress > 100) progress = 0;
const offset = circumference - (progress / 100) * circumference;
circle.style.strokeDashoffset = offset;
percentageEl.textContent = progress;
}
setInterval(updateProgress, 50);
SVG en JavaScript technieken:
stroke-dasharray: Bepaalt lengte van de stroke (circumference van cirkel)stroke-dashoffset: Offset die de "gevulde" lengte bepaalttransform: rotate(-90deg): Start progress op 12 uur positiestroke-linecap: round: Ronde uiteinden voor moderne lookReal-world gebruik: Perfect voor file uploads, API requests of multi-step forms waar je exacte voortgang wilt tonen.
Modern alternatief voor spinners. Toon een "skelet" van de content die gaat laden. Dit geeft gebruikers een preview en vermindert de ervaren wachttijd.
<div class="card-skeleton">
<div class="skeleton-header">
<div class="skeleton-avatar"></div>
<div class="skeleton-author">
<div class="skeleton-title"></div>
<div class="skeleton-subtitle"></div>
</div>
</div>
<div class="skeleton-image"></div>
<div class="skeleton-text"></div>
<div class="skeleton-text short"></div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f5f5f5;
padding: 20px;
}
.card-skeleton {
width: 100%;
max-width: 400px;
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.skeleton-header {
display: flex;
gap: 12px;
margin-bottom: 16px;
}
.skeleton-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
.skeleton-author {
flex: 1;
}
.skeleton-title {
height: 16px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
margin-bottom: 8px;
}
.skeleton-subtitle {
height: 12px;
width: 60%;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
}
.skeleton-image {
height: 200px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 8px;
margin-bottom: 16px;
}
.skeleton-text {
height: 12px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
margin-bottom: 8px;
}
.skeleton-text.short {
width: 70%;
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
Skeleton screen principes:
linear-gradient met 3 stops: Creëert het "glans" effectbackground-size: 200%: Maakt gradient 2x breder voor smooth animatiebackground-position animatie: Beweegt gradient van links naar rechtsUX voordeel: Onderzoek toont aan dat skeleton screens de ervaren wachttijd met 30% verminderen vergeleken met spinners. Wil je meer weten over website snelheid testen? Bekijk onze gids met de 5 beste tools.
Een eye-catching 3D cube loader die roteert in alle richtingen. Gebruikt CSS 3D transforms voor een premium look.
<div class="scene">
<div class="cube">
<div class="cube-face front"></div>
<div class="cube-face back"></div>
<div class="cube-face right"></div>
<div class="cube-face left"></div>
<div class="cube-face top"></div>
<div class="cube-face bottom"></div>
</div>
</div>
body {
margin: 0;
overflow: hidden;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.scene {
width: 80px;
height: 80px;
perspective: 600px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation: rotate 3s infinite linear;
}
.cube-face {
position: absolute;
width: 80px;
height: 80px;
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
}
.front { transform: rotateY(0deg) translateZ(40px); }
.back { transform: rotateY(180deg) translateZ(40px); }
.right { transform: rotateY(90deg) translateZ(40px); }
.left { transform: rotateY(-90deg) translateZ(40px); }
.top { transform: rotateX(90deg) translateZ(40px); }
.bottom { transform: rotateX(-90deg) translateZ(40px); }
@keyframes rotate {
0% {
transform: rotateX(0deg) rotateY(0deg);
}
100% {
transform: rotateX(360deg) rotateY(360deg);
}
}
3D CSS eigenschappen:
perspective: 600px: Bepaalt de "camera afstand" voor 3D effecttransform-style: preserve-3d: Zorgt dat child elements in 3D space blijventranslateZ(): Positioneert elke face op juiste diepte (40px = halve breedte)rotateX() en rotateY(): Creëert rotatie op beide assen tegelijkbackdrop-filter: Moderne glasmorphism effect op cube facesEen moderne horizontale progress bar met vloeiend bewegende gradient. Ideaal voor file uploads of multi-step processen.
<div class="progress-wrapper">
<div class="progress-label">Uploading...</div>
<div class="progress-bar-container">
<div class="progress-bar" id="progressBar"></div>
</div>
<div class="progress-stats">
<span id="progressPercent">0%</span>
<span>2.4 MB / 10 MB</span>
</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #2c2c3e;
font-family: 'Inter', sans-serif;
}
.progress-wrapper {
width: 400px;
padding: 30px;
background: #3a3a52;
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
.progress-label {
font-size: 18px;
font-weight: 600;
color: #fff;
margin-bottom: 12px;
}
.progress-bar-container {
width: 100%;
height: 8px;
background: #2a2a3e;
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #667eea, #764ba2, #f093fb);
background-size: 200% 100%;
border-radius: 4px;
animation: gradient-flow 2s linear infinite;
transition: width 0.3s ease;
}
.progress-stats {
display: flex;
justify-content: space-between;
font-size: 14px;
color: #a0a0b8;
}
#progressPercent {
color: #667eea;
font-weight: 600;
}
@keyframes gradient-flow {
0% {
background-position: 0% 0%;
}
100% {
background-position: 200% 0%;
}
}
const progressBar = document.getElementById('progressBar');
const progressPercent = document.getElementById('progressPercent');
let progress = 0;
function simulateProgress() {
if (progress < 100) {
progress += Math.random() * 10;
if (progress > 100) progress = 100;
progressBar.style.width = progress + '%';
progressPercent.textContent = Math.floor(progress) + '%';
setTimeout(simulateProgress, 300);
} else {
setTimeout(() => {
progress = 0;
progressBar.style.width = '0%';
progressPercent.textContent = '0%';
simulateProgress();
}, 1000);
}
}
simulateProgress();
Progress bar technieken:
width transition: Smooth groei van progress baroverflow: hidden: Houdt rounded corners intact tijdens animatieConcentrische cirkels die uitbreiden zoals water ripples. Elegant en subtiel, perfect voor achtergrond loading states.
<div class="ripple-container">
<div class="ripple"></div>
<div class="ripple"></div>
<div class="ripple"></div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #0a0a0f;
}
.ripple-container {
position: relative;
width: 100px;
height: 100px;
}
.ripple {
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
transform: translate(-50%, -50%);
border-radius: 50%;
border: 3px solid #00d9ff;
animation: ripple 3s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
.ripple:nth-child(2) {
animation-delay: 1s;
}
.ripple:nth-child(3) {
animation-delay: 2s;
}
@keyframes ripple {
0% {
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 100px;
height: 100px;
opacity: 0;
}
}
Ripple animatie principes:
cubic-bezier easing: Custom timing function voor natuurlijke versnellingborder vs background: Border gebruikt minder pixels voor betere performanceVariatie tip: Verander border naar box-shadow voor glow ripples. Of gebruik meerdere kleuren voor een rainbow effect.
De meest herkenbare loader. Een roterende cirkel met partial border. Moderne twist met gradient kleuren.
<div class="spinner"></div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #16161d;
}
.spinner {
width: 60px;
height: 60px;
border: 6px solid rgba(255, 255, 255, 0.1);
border-top-color: #667eea;
border-right-color: #764ba2;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
Spinner basics:
Twee concentrische ringen die in tegengestelde richting roteren voor een hypnotiserend effect.
<div class="dual-ring-container">
<div class="ring outer"></div>
<div class="ring inner"></div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #1a1a2e;
}
.dual-ring-container {
position: relative;
width: 80px;
height: 80px;
}
.ring {
position: absolute;
border-radius: 50%;
border: 4px solid transparent;
}
.outer {
width: 80px;
height: 80px;
border-top-color: #00d9ff;
border-right-color: #00d9ff;
animation: spin 1.2s linear infinite;
}
.inner {
width: 50px;
height: 50px;
top: 15px;
left: 15px;
border-top-color: #ff006e;
border-left-color: #ff006e;
animation: spin-reverse 1.2s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@keyframes spin-reverse {
to { transform: rotate(-360deg); }
}
Dual rotation techniek:
Drie ballen die springen met realistische physics, zwaartekracht en elasticity.
<div class="bouncing-balls">
<div class="ball"></div>
<div class="ball"></div>
<div class="ball"></div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #2d2d44;
}
.bouncing-balls {
display: flex;
gap: 12px;
align-items: flex-end;
height: 80px;
}
.ball {
width: 20px;
height: 20px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 50%;
animation: bounce 0.6s cubic-bezier(0.28, 0.84, 0.42, 1) infinite;
}
.ball:nth-child(1) {
animation-delay: 0s;
}
.ball:nth-child(2) {
animation-delay: 0.2s;
}
.ball:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes bounce {
0%, 100% {
transform: translateY(0) scaleY(1);
}
50% {
transform: translateY(-60px) scaleY(1);
}
90% {
transform: translateY(0) scaleY(0.8) scaleX(1.2);
}
}
Physics simulation:
cubic-bezier easing: Imiteert zwaartekracht en bouncescaleY(0.8) scaleX(1.2): Squash effect bij landingTekst-based loader waarbij dots één voor één verschijnen en verdwijnen. Geen afbeeldingen nodig.
<div class="loading-text">
Loading<span class="dots"><span>.</span><span>.</span><span>.</span></span>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #0f0f23;
font-family: 'Courier New', monospace;
}
.loading-text {
font-size: 32px;
color: #00d9ff;
font-weight: 700;
}
.dots span {
animation: blink 1.4s infinite;
opacity: 0;
}
.dots span:nth-child(1) {
animation-delay: 0s;
}
.dots span:nth-child(2) {
animation-delay: 0.2s;
}
.dots span:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes blink {
0%, 20% {
opacity: 0;
}
40% {
opacity: 1;
}
100% {
opacity: 0;
}
}
Text animation voordelen:
Cyberpunk-stijl glitch effect op loading text. Perfect voor tech en gaming websites.
<div class="glitch" data-text="LOADING">LOADING</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #000;
overflow: hidden;
}
.glitch {
position: relative;
font-size: 64px;
font-weight: 900;
color: #fff;
letter-spacing: 8px;
animation: glitch-skew 1s infinite;
}
.glitch::before,
.glitch::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glitch::before {
left: 2px;
text-shadow: -2px 0 #ff00de;
clip: rect(24px, 550px, 90px, 0);
animation: glitch-anim 2s infinite linear alternate-reverse;
}
.glitch::after {
left: -2px;
text-shadow: -2px 0 #00fff9;
clip: rect(85px, 550px, 140px, 0);
animation: glitch-anim 3s infinite linear alternate-reverse;
}
@keyframes glitch-skew {
0% {
transform: skew(0deg);
}
10% {
transform: skew(-2deg);
}
20% {
transform: skew(2deg);
}
30% {
transform: skew(0deg);
}
}
@keyframes glitch-anim {
0% {
clip: rect(33px, 9999px, 94px, 0);
}
20% {
clip: rect(10px, 9999px, 73px, 0);
}
40% {
clip: rect(85px, 9999px, 40px, 0);
}
60% {
clip: rect(65px, 9999px, 119px, 0);
}
80% {
clip: rect(24px, 9999px, 62px, 0);
}
100% {
clip: rect(91px, 9999px, 34px, 0);
}
}
Glitch effect techniek:
attr(data-text): Duplicate text via CSS content propertyclip: rect(): Toont alleen specifieke delen van pseudo-elementstext-shadow kleuren: Cyan en magenta voor RGB split effectToon exacte loading percentage met smooth counting animatie van 0 tot 100.
<div class="counter-wrapper">
<div class="counter" id="counter">0</div>
<div class="counter-label">%</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
font-family: 'Inter', sans-serif;
}
.counter-wrapper {
display: flex;
align-items: baseline;
gap: 8px;
}
.counter {
font-size: 120px;
font-weight: 900;
color: #fff;
line-height: 1;
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}
.counter-label {
font-size: 48px;
color: rgba(255, 255, 255, 0.8);
font-weight: 700;
}
const counter = document.getElementById('counter');
const duration = 3000; // 3 seconds
const start = 0;
const end = 100;
const startTime = Date.now();
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}
function animateCounter() {
const now = Date.now();
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
const easedProgress = easeOutCubic(progress);
const current = Math.floor(start + (end - start) * easedProgress);
counter.textContent = current;
if (progress < 1) {
requestAnimationFrame(animateCounter);
} else {
// Reset after completion
setTimeout(() => {
counter.textContent = '0';
animateCounter();
}, 1000);
}
}
animateCounter();
Counter animatie principes:
requestAnimationFrame: Sync met browser refresh rate voor smoothnessTime-based: Gebruikt elapsed time, niet frame countMath.floor(): Voorkomt decimal numbers in displayVisuele weergave van multi-step processen. Met actieve state indicators.
<div class="steps-container">
<div class="step active">
<div class="step-number">1</div>
<div class="step-label">Account</div>
</div>
<div class="step-line"></div>
<div class="step active">
<div class="step-number">2</div>
<div class="step-label">Payment</div>
</div>
<div class="step-line"></div>
<div class="step">
<div class="step-number">3</div>
<div class="step-label">Confirm</div>
</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #f8f9fa;
font-family: 'Inter', sans-serif;
}
.steps-container {
display: flex;
align-items: center;
gap: 0;
}
.step {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.step-number {
width: 48px;
height: 48px;
border-radius: 50%;
background: #e0e0e0;
color: #999;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: 700;
transition: all 0.3s ease;
}
.step.active .step-number {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
.step-label {
font-size: 14px;
color: #999;
font-weight: 500;
transition: color 0.3s ease;
}
.step.active .step-label {
color: #333;
font-weight: 600;
}
.step-line {
width: 80px;
height: 3px;
background: #e0e0e0;
margin: 0 -8px 20px -8px;
}
Multi-step design:
.active class: JavaScript toggled state voor current stepVoor processen waar je niet weet hoelang het duurt, gebruik een oneindige bewegende bar.
<div class="indeterminate-container">
<div class="indeterminate-bar"></div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #1a1a2e;
}
.indeterminate-container {
width: 300px;
height: 4px;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
overflow: hidden;
}
.indeterminate-bar {
width: 40%;
height: 100%;
background: linear-gradient(90deg, transparent, #00d9ff, transparent);
animation: indeterminate 1.5s cubic-bezier(0.65, 0.05, 0.36, 1) infinite;
}
@keyframes indeterminate {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(350%);
}
}
Indeterminate techniek:
translateX range: -100% tot 350% voor volledige traverseoverflow: hidden: Verbergt bar buiten containerToon meerdere simultane processen met individuele progress bars.
<div class="multi-progress">
<div class="process">
<div class="process-label">Uploading files</div>
<div class="process-bar">
<div class="process-fill" style="width: 75%"></div>
</div>
</div>
<div class="process">
<div class="process-label">Processing images</div>
<div class="process-bar">
<div class="process-fill" style="width: 45%"></div>
</div>
</div>
<div class="process">
<div class="process-label">Generating thumbnails</div>
<div class="process-bar">
<div class="process-fill" style="width: 20%"></div>
</div>
</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #2c2c3e;
font-family: 'Inter', sans-serif;
}
.multi-progress {
width: 400px;
padding: 24px;
background: #3a3a52;
border-radius: 12px;
display: flex;
flex-direction: column;
gap: 20px;
}
.process-label {
font-size: 14px;
color: #a0a0b8;
margin-bottom: 8px;
}
.process-bar {
width: 100%;
height: 6px;
background: #2a2a3e;
border-radius: 3px;
overflow: hidden;
}
.process-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 3px;
transition: width 0.5s ease;
}
Multi-process UI:
Dubbele helix structuur die roteert. Visueel interessant en uniek.
<div class="dna-loader">
<div class="strand">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="strand">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #0a0a0f;
}
.dna-loader {
position: relative;
width: 100px;
height: 100px;
}
.strand {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
animation: rotate 2s linear infinite;
}
.strand:nth-child(2) {
animation-delay: -1s;
}
.dot {
width: 12px;
height: 12px;
background: linear-gradient(135deg, #00d9ff, #0088ff);
border-radius: 50%;
box-shadow: 0 0 10px #00d9ff;
}
@keyframes rotate {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
3D rotation:
rotateY(360deg): Rotatie op Y-as voor helix effectanimation-delay: -1s: Start tweede strand halverwegeGeanimeerde hartslag lijn zoals je ziet op medische monitors.
<div class="ekg-container">
<svg class="ekg" viewBox="0 0 200 60">
<polyline class="ekg-line" points="0,30 40,30 45,10 50,50 55,30 200,30" />
</svg>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #0a0a0a;
}
.ekg-container {
width: 400px;
height: 120px;
background: #1a1a1a;
border-radius: 8px;
padding: 20px;
box-shadow: 0 0 20px rgba(0, 255, 136, 0.2);
}
.ekg {
width: 100%;
height: 100%;
}
.ekg-line {
fill: none;
stroke: #00ff88;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 200;
stroke-dashoffset: 200;
animation: ekg-pulse 2s linear infinite;
filter: drop-shadow(0 0 4px #00ff88);
}
@keyframes ekg-pulse {
0% {
stroke-dashoffset: 200;
}
100% {
stroke-dashoffset: 0;
}
}
SVG line animation:
stroke-dasharray & dashoffset: Tekent lijn geleidelijkfilter: drop-shadow: SVG glow effectIconic Matrix-style vallende karakters als loading indicator.
<div class="matrix-container">
<div class="matrix-column">
<span>1</span><span>0</span><span>1</span>
<span>0</span><span>1</span>
</div>
<div class="matrix-column">
<span>0</span><span>1</span><span>0</span>
<span>1</span>
</div>
<div class="matrix-column">
<span>1</span><span>1</span><span>0</span>
<span>0</span><span>1</span>
</div>
<div class="matrix-column">
<span>0</span><span>1</span><span>1</span>
<span>0</span>
</div>
</div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #000;
overflow: hidden;
}
.matrix-container {
display: flex;
gap: 20px;
font-family: 'Courier New', monospace;
font-size: 20px;
}
.matrix-column {
display: flex;
flex-direction: column;
animation: fall 3s linear infinite;
}
.matrix-column:nth-child(1) { animation-delay: 0s; }
.matrix-column:nth-child(2) { animation-delay: 0.5s; }
.matrix-column:nth-child(3) { animation-delay: 1s; }
.matrix-column:nth-child(4) { animation-delay: 1.5s; }
.matrix-column span {
color: #00ff41;
opacity: 0;
animation: fade 0.5s ease-in-out infinite;
}
.matrix-column span:nth-child(1) { animation-delay: 0s; }
.matrix-column span:nth-child(2) { animation-delay: 0.2s; }
.matrix-column span:nth-child(3) { animation-delay: 0.4s; }
.matrix-column span:nth-child(4) { animation-delay: 0.6s; }
.matrix-column span:nth-child(5) { animation-delay: 0.8s; }
@keyframes fall {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(100vh);
}
}
@keyframes fade {
0%, 100% {
opacity: 0;
}
50% {
opacity: 1;
}
}
Matrix effect:
translateY(100vh): Beweegt van boven naar benedenShape die morfheert tussen cirkel, vierkant en driehoek is hypnotiserend en modern.
<div class="morph-loader"></div>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.morph-loader {
width: 80px;
height: 80px;
background: white;
animation: morph 3s ease-in-out infinite;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
@keyframes morph {
0% {
border-radius: 50%;
transform: rotate(0deg);
}
33% {
border-radius: 0%;
transform: rotate(120deg);
}
66% {
border-radius: 50% 0% 50% 0%;
transform: rotate(240deg);
}
100% {
border-radius: 50%;
transform: rotate(360deg);
}
}
Shape morphing:
border-radius variaties: 50% = cirkel, 0% = vierkantVariatie tip: Experimenteer met verschillende border-radius waarden voor unieke shapes.
Niet iedereen houdt van animaties. Sommige gebruikers ervaren misselijkheid, duizeligheid of afleiding door bewegende elementen. Dit heet vestibular motion sensitivity en treft naar schatting 35% van volwassenen boven de 40 jaar.
Moderne browsers ondersteunen de prefers-reduced-motion media query. Hiermee kun je animaties uitschakelen of vereenvoudigen voor gebruikers die dit hebben ingesteld:
/* Standaard: animatie actief */
.loader {
animation: spin 1s linear infinite;
}
/* Voor gebruikers die reduced motion prefereren */
@media (prefers-reduced-motion: reduce) {
.loader {
animation: none;
/* Toon statische indicator of subtiele opacity pulse */
opacity: 0.7;
}
}
Best practices voor toegankelijke loading animaties:
prefers-reduced-motion om animaties uit te schakelenaria-label="Laden..." toe aan je loader elementaria-live="polite" voor screen readersAlle 20 voorbeelden in dit artikel zijn getest op Chrome 120, Firefox 121 en Safari 17. Elke animatie haalt 60fps op mid-range devices dankzij GPU-accelerated properties (transform, opacity).
Kies de juiste loading animatie op basis van je use case:
| Type | Gebruik wanneer | Duur | Voorbeelden |
|---|---|---|---|
| Spinner | Korte, onbepaalde wachttijd | < 2 sec | API |
| Skeleton screen | Content layout bekend | 1-5 sec | Feed items, cards, product listings |
| Progress bar | Voortgang meetbaar | 5+ sec | File upload, download, installatie |
| Typing indicator | Wachten op andere partij | Onbepaald | Chat, AI responses, live updates |
| Multi-step | Meerdere stappen in proces | Varies | Checkout, onboarding, wizards |
Vuistregel: Hoe langer de wachttijd, hoe meer informatie je moet geven. Onder 2 seconden volstaat een simpele spinner. Boven 5 seconden wil de gebruiker exacte voortgang zien.
Na het bekijken van deze 20 voorbeelden wil je misschien meer mogelijkheden verkennen. Hier zijn drie essentiële tools die je helpen bij het bouwen van loading animaties.
GSAP is dé JavaScript animation library voor professionele animaties. Met 11 miljoen downloads per maand en 16k+ GitHub
KeurigOnline zegtGithubGitHub is een platform voor versiebeheer en samenwerking aan code. Onze pakketten ondersteunen SSH en git. stars is het de industry standard.
GSAP biedt timeline control, easing functions en performance optimization out-of-the-box. Perfect voor complexe loading sequences waar je meerdere elementen moet orchestreren.
De library is slechts 50KB (gzipped) maar levert GPU-accelerated animaties die 20x sneller zijn dan jQuery. Ideaal voor production-ready loading states.
Lottie van Airbnb rendert After Effects animaties real-time. Designers maken complexe animaties in After Effects en exporteren als JSON
KeurigOnline zegtJSONJSON is een lichtgewicht dataformaat voor het uitwisselen van gegevens tussen systemen.. Developers embedden ze met 3 regels code.
De library is slechts 35KB maar ondersteunt kleur changes, playback control en interactieve triggers. Perfect voor custom brand animaties zonder handmatig CSS te schrijven.
Lottie files zijn vector-based, dus ze schalen perfect naar elke schermgrootte zonder kwaliteitsverlies. Cruciaal voor responsive designs.
CSS Loaders is een verzameling van 600+ pure CSS
KeurigOnline zegtCSSCSS is de stijltaal waarmee je de visuele opmaak en layout van HTML-pagina’s bepaalt. loading animaties. Elk voorbeeld komt met copy-paste code en live preview.
De collectie gebruikt alleen CSS zonder JavaScript, wat betekent instant loading en zero dependencies. Sorteer op style (spinner, bars, dots) of complexity (simple, medium, advanced).
Alle loaders zijn geoptimaliseerd voor performance met GPU-accelerated properties (transform, opacity). Perfect startpunt voor je eigen custom variaties.
Loading animaties zijn onmisbaar voor moderne websites, of niet?
Een goed gekozen loading animatie verbetert de gebruikerservaring drastisch. Maar overdrijf niet. Te veel animaties, te lange duur of te complexe effecten veroorzaken irritatie. De beste loading indicator is er één die je gebruiker nauwelijks opmerkt omdat je website razendsnel laadt.
Gebruik de 20 voorbeelden uit dit artikel als inspiratie en pas ze aan voor jouw brand en doelgroep. Start met simpele spinners voor korte loads (< 2 seconden). Gebruik skeleton screens voor content-heavy paginas en reserveer progress bars voor file uploads waar gebruikers exacte voortgang willen zien.
Test altijd op echte devices en meet of je animatie de ervaren wachttijd daadwerkelijk verkort. Bekijk ook onze andere frontend tutorials: CSS button designs met 20 voorbeelden en .htaccess snippets voor snellere websites.
Bij KeurigOnline zorgen we ervoor dat je loading animaties zo kort mogelijk draaien. Onze LiteSpeed-servers met NVMe
KeurigOnline zegtNVMeNVMe is ultrasnelle SSD-opslag die websites tot 6x sneller maakt dan traditionele opslag.-opslag leveren laadtijden onder 0,8s, waardoor je gebruikers minder wachten en meer converteren.
Wil je hulp bij het optimaliseren van je website performance? Onze support uit Groningen staat klaar met 77% reactietijd onder 1 minuut.
Een loading animatie is een visuele indicator die gebruikers laat zien dat een website of applicatie bezig is met het laden van content. Dit kan een roterende spinner, skeleton screen, progress bar of typing indicator zijn. Loading animaties geven feedback tijdens wachttijd en verminderen de ervaren laadtijd met gemiddeld 30%.
De belangrijkste CSS properties voor loading animaties zijn @keyframes voor de animatie definitie, animation voor timing en herhaling, en transform met opacity voor GPU-accelerated beweging. Gebruik altijd transform (rotate, scale, translate) in plaats van width/height voor 60fps performance.
Een spinner is een roterende indicator voor korte, onbekende wachttijden (onder 2 seconden). Een skeleton screen toont een placeholder van de content layout en is beter voor langere loads (1-5 seconden) waar de structuur bekend is. Onderzoek toont dat skeleton screens de ervaren wachttijd met 30% verkorten vergeleken met spinners.
Een CSS spinner maak je met een cirkel (border-radius: 50%) met een gedeeltelijk gekleurde border (border-top-color) en een oneindige rotate animatie. De basis code is: .spinner { border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; } met @keyframes spin { to { transform: rotate(360deg); } }.
Gebruik een progress bar wanneer je de exacte voortgang kunt meten, zoals bij file uploads, downloads of multi-step formulieren. Progress bars zijn ideaal voor processen langer dan 5 seconden. Voor onbekende duur gebruik je een indeterminate progress bar met een bewegende gradient in plaats van een vaste percentage.
Maak loading animaties toegankelijk door de prefers-reduced-motion media query te gebruiken om animaties uit te schakelen voor gevoelige gebruikers. Voeg aria-label="Laden..." toe aan het loader element en gebruik aria-live="polite" voor screen readers. Vermijd flitsende animaties (max 3 per seconde volgens WCAG 2.3.1).
De beste loading animaties voor performance gebruiken alleen transform en opacity properties, omdat deze GPU-accelerated zijn. Vermijd animaties op width, height, margin of padding. Pure CSS animaties zijn sneller dan JavaScript
KeurigOnline zegtJavaScriptJavaScript is de browser- en server-scriptingtaal voor interactieve, asynchrone webapplicaties.. Een simpele spinner met transform: rotate() is de meest performante optie met minimale impact op Core Web Vitals
KeurigOnline zegtCore Web VitalsCore Web Vitals zijn Google's belangrijkste metrics voor website-ervaring en snelheid..
Toon een loader door het element zichtbaar te maken met document.getElementById('loader').style.display = 'flex' bij het starten van een AJAX request. Verberg na completion met style.display = 'none' in de callback of .then() van een fetch. Gebruik CSS transitions voor smooth fade-in/fade-out effecten.
De drie beste libraries zijn GSAP (GreenSock) voor complexe sequenties met 50KB footprint, Lottie van Airbnb voor After Effects animaties als JSON
KeurigOnline zegtJSONJSON is een lichtgewicht dataformaat voor het uitwisselen van gegevens tussen systemen. (35KB), en CSS Loaders voor 600+ pure CSS voorbeelden zonder dependencies. Voor simpele loaders is pure CSS vaak voldoende en sneller dan een library.
Gebruikers accepteren maximaal 2-3 seconden wachttijd voordat ze afhaken. Voor loads onder 1 seconde is vaak geen loader nodig. Tussen 1-3 seconden gebruik je een spinner. Boven 3 seconden toon je een progress bar met percentage of geef feedback over wat er gebeurt. De beste oplossing is altijd je website sneller maken zodat loaders niet nodig zijn.
Laatst gecontroleerd: december 2024