CSS-lab · Loaders
Brutalist blokken-loader
Drie vierkante blokken met harde cobalt schaduw springen om de beurt omhoog, kleuren acid in de lucht en landen met een korte squash.
- Beginner
- Pure CSS
- MIT-licentie
@keyframestransformtransform-originanimation-delaycalc()
<div class="bl-loader" role="status">
<span class="bl-block" aria-hidden="true"></span>
<span class="bl-block" aria-hidden="true"></span>
<span class="bl-block" aria-hidden="true"></span>
<span class="bl-sr">Bezig met laden</span>
</div>/* Brutalist blokken-loader — prefix .bl- */
.bl-loader {
--size: 26px;
--gap: 12px;
--block: #F9F8F6;
--accent: #C6FF3D;
--shadow: #2E5BFF;
--speed: 1.2s;
position: relative;
display: inline-flex;
align-items: flex-end;
gap: var(--gap);
/* ruimte voor de sprong */
padding-top: calc(var(--size) * 1.4);
padding-bottom: 10px;
}
/* vloerlijn */
.bl-loader::after {
content: "";
position: absolute;
left: -8px;
right: -8px;
bottom: 0;
height: 2px;
background: rgba(249, 248, 246, .35);
}
.bl-block {
width: var(--size);
height: var(--size);
background: var(--block);
box-shadow: 4px 4px 0 var(--shadow);
/* squash vanaf de vloer */
transform-origin: 50% 100%;
animation: bl-jump var(--speed) cubic-bezier(.45, 0, .55, 1) infinite;
}
/* om de beurt */
.bl-block:nth-child(2) {
animation-delay: calc(var(--speed) / 6);
}
.bl-block:nth-child(3) {
animation-delay: calc(var(--speed) / 3);
}
@keyframes bl-jump {
0%, 55%, 100% {
transform: translateY(0) scale(1, 1);
background-color: var(--block);
}
20% {
transform: translateY(calc(var(--size) * -1.2)) scale(.94, 1.08);
background-color: var(--accent);
}
38% {
transform: translateY(0) scale(1.18, .82);
background-color: var(--accent);
}
46% {
transform: translateY(0) scale(.96, 1.04);
}
}
/* tekst alleen voor screenreaders */
.bl-sr {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
clip-path: inset(50%);
white-space: nowrap;
}
/* geen sprong, wel een rustige puls */
@media (prefers-reduced-motion: reduce) {
.bl-block {
animation: bl-pulse calc(var(--speed) * 2.5) ease-in-out infinite;
}
.bl-block:nth-child(2) { animation-delay: .4s; }
.bl-block:nth-child(3) { animation-delay: .8s; }
}
@keyframes bl-pulse {
0%, 100% { background-color: var(--block); }
50% { background-color: var(--accent); }
}Wat het is en waar je het gebruikt
Een spinner is vaak het saaiste element op een pagina. Deze brutalist blokken-loader is dat niet: drie vierkante blokken in off-white met een harde cobalt offset-schaduw springen één voor één omhoog. Bovenin kleuren ze acid lime, en bij de landing worden ze heel even platgedrukt, alsof ze echt gewicht hebben. Onder de blokken ligt een dunne vloerlijn, zodat de sprong een vast referentiepunt heeft.
Gebruik hem bij het laden van een dashboard, een formulier dat wordt verstuurd, een zoekresultaat of als splash bij een webapp. Hij is klein genoeg voor in een knop of kaart en karaktervol genoeg om op een leeg scherm te staan.
Zo werkt het
- Eén keyframe-reeks:
@keyframes bl-jumpbeschrijft de hele beweging: rust, omhoog mettranslateY, terug naar beneden en een squash metscale(1.18, .82). Tegelijk wisseltbackground-colornaar--accentop het hoogste punt. - Om de beurt: de blokken delen dezelfde animatie. Met
:nth-child(2)en:nth-child(3)krijgen ze eenanimation-delayvan een zesde en een derde van--speed, berekend metcalc(). Zo blijft het ritme kloppen als je de snelheid verandert. - Squash vanaf de bodem:
transform-origin: 50% 100%zorgt dat het blok bij het platdrukken op de vloer blijft staan in plaats van te zweven. - Harde schaduw:
box-shadow: 4px 4px 0 var(--shadow)zonder blur geeft het brutalistische, gedrukte karakter.
Aanpassen
Op .bl-loader staan --size (blokgrootte), --gap (ruimte tussen de blokken), --block (ruststandkleur), --accent (kleur in de lucht), --shadow en --speed (duur van één cyclus). De spronghoogte is gekoppeld aan --size, dus een grotere loader springt automatisch hoger. Wil je vier blokken, voeg dan een span toe en een extra :nth-child(4) met een langere delay.
Toegankelijkheid en browsersupport
De container heeft role="status" en bevat een visueel verborgen tekst “Bezig met laden”, zodat screenreaders weten wat er gebeurt. De blokken zelf zijn aria-hidden="true". Met prefers-reduced-motion: reduce springen ze niet meer, maar pulseren ze rustig in kleur, zodat er nog wel zichtbaar iets gebeurt. Alleen transform wordt geanimeerd voor de beweging, wat soepel loopt. Werkt in alle actuele browsers.
Verder lezen
Een loader is een van de meest onderschatte microinteracties: hij bepaalt hoe lang wachten voelt. Lees meer in microinteracties in UX. Wil je dat elk wachtmoment in je product bij je merk past, kijk dan naar interactief webdesign en animaties.
Meer loaders
