Ladeelemente in CSS
Keine Lust zu warten? Durch sinnvoll gestaltete Ladeelemente im Webdesign wird dem User während Wartezeiten vermittelt, dass es weiter geht. Vermeide unnötige Verwirrungen bei längeren Wartezeiten und folge diesem Tutorial für visuell ansprechende Ladebalken und das entsprechende Know-How!
Im Folgenden stellen wir die Grundstruktur von Ladebalken mit Animationen vor und zeigen dann mit ausführlichen Codebeispielen wie auch andere Ladeelemente in CSS schön gestaltet werden können. Vorausgesetzt ist ein Grundverständnis bezüglich HTML und CSS und deren Verknüpfung via class
-Attribut.
Grundaufbau
<div class="lade-container">
<div class="lade-balken"></div>
</div>
Der Ladebalken auf der HTML-Ebene ist ein <div>
-Element. Die Struktur besteht hier aus einem äußeren Container und einem inneren Balken.
.lade-container
= Rahmen für den Balken.lade-balken
= animierter Fortschrittsbalken
.lade-balken {
width: 0%;
animation: ladeanimation 3s linear forwards;
}
@keyframes ladeanimation {
to { width: 100%; }
}
animation
steuert den Fortschritt des Balkens. In dieser Anweisung werden Richtung, Dauer und der Link zu den entsprechenden Frames mitgeteilt. Die definierten Frames sind außerhalb von .lade-balken
in der @keyframes
-Anweisung zu finden. In diesem einfachen Balken gibt es nur einen Zielframe der bei 100% erreicht wird. Hier wird also die volle länge des Balkens nach 3 Sekunden erreicht.
width
dient als die visuelle Fortschrittsanzeige des Balkens
Klassischer Ladebalken mit Loop
@keyframes ladeanimation1 {
0% { width: 0%; }
66% { width: 100%; }
83% { width: 100%; } /* kurze Pause */
100% { width: 0%; } /* zurück auf Anfang */
}
In diesem Ladebalken 66 % der Zeit ist der Balken vollständig gefüllt. Von 66% bis 83% der abgelaufenen Animation verharrt der Balken auf maximaler Breite. Danach fährt er dynamisch zurück auf Startposition. Diese Abfolge mit den verschiedenen Frames ist der @keyfames
-Anweisung zu entnehmen.
Ladebalken mit Prozentzahl
<div class="prozent-2" id="prozent2">0%</div>
let wert2 = 0;
setInterval(() => {
balken2.style.width = wert2 + '%';
prozent2.textContent = wert2 + '%';
wert2++;
}, 40);
Als Ausgangslage zeigt der Balken »0%« an. Durch JavaScript passt sich der Stand des Balkens und die Prozentanzeige an den Counter an. Dabei verändert style.width
den Balken und textContent
zeigt live den Wert. Der Stand wird jede 400ms um 1% erhöht, sodass eine flüssige Animation entsteht.
Kreisförmiger Ladebalken
<circle class="kreis-bg" cx="80" cy="80" r="70" />
<circle class="kreis-fortschritt" cx="80" cy="80" r="70" />
.kreis-fortschritt {
stroke-dasharray: 440;
stroke-dashoffset: 440;
}
const umfang = 2 * Math.PI * 70;
const offset = umfang - (wert / 100) * umfang;
kreis.style.strokeDashoffset = offset;
In HTML wird hier ein Kreis erstellt. Im CSS-Part wird mit stroke-dasharray
die Länge des Umfangs bestimmt und mit stroke-dashoffset
die initiale »Verdeckung«. mit JavaScript wird dann immer mehr von dem Kreis enthüllt.
Unregelmäßiger Ladebalken
const step = Math.random() * 15 + 5;
wert += step;
die Variable step
hat einen Zufallswert zwischen 5 und 20 %. Dadurch springt der Ladebalken unregelmäßig weiter.
Alle Balkenarten nutzen dieselbe Grundstruktur (
div
odercircle
)Fortschritt wird meist per
width
(div) oderstrokeDashoffset
(SVG) gesteuertJavaScript ist nur nötig, wenn der Fortschritt dynamisch sein soll
Weitere Ladeelemente
Die folgenden Ladeelemente funktionieren auf sehr unterschiedlichen Methoden. Es werdenfür Animatinen immer @keyframe
-Anweisungen benutzt, aber der grafische Aufbau, Die Nutzung von Pseudoelemente und die Komplexität der Animation variiert je nach Ladeelement. Daher beschreiben wir wir für jedes Ladeelement nur die wichtigsten Abschnitte zum Codeverständnis und vertrauen darauf, dass du übrige Fragen mit Hilfe eines LLM klären kannst.
Loading - Schrift
.element4 {
width: fit-content;
font-size: 2.5rem;
font-family: system-ui,sans-serif;
font-weight: bold;
text-transform: uppercase;
color: #0000;
-webkit-text-stroke: 1px #000;
background: conic-gradient(#FF3344 0 0) 0/0% 100% no-repeat text; /*BackgroundWidth Start */
animation: l1 1s linear infinite;
}
@keyframes l1 {
to{background-size: 120% 100%} /*BackgroundWidth End */
}
<div class="element4">Loading</div>
Ähnlich wie beim normalen Ladebalken wird hier über eine @keyframes
-Animation progressiv der Hintergrund expandiert. Über verschiedenste CSS-Anweisungen lässt sich das Schriftbild und die Farbe verändern. Im <div>
Element steht hier das Wort, dass zum Ladebalken wird.
Geometrische Animation
.element2 {
width: 2.5rem;
height: 2.5rem;
color: #ff3344;
background:
conic-gradient(from -45deg at top 20px left 50% ,#0000 ,currentColor 1deg 90deg,#0000 91deg),
conic-gradient(from 45deg at right 20px top 50% ,#0000 ,currentColor 1deg 90deg,#0000 91deg),
conic-gradient(from 135deg at bottom 20px left 50% ,#0000 ,currentColor 1deg 90deg,#0000 91deg),
conic-gradient(from -135deg at left 20px top 50% ,#0000 ,currentColor 1deg 90deg,#0000 91deg);
animation: l4 1.5s infinite cubic-bezier(0.3,1,0,1); /* Beschleunigung der Animation */
}
@keyframes l4 {
50% {width:3.75rem;height: 3.75rem;transform: rotate(180deg)} /* Maximalgröße 3.75rem */
100% {transform: rotate(360deg)}
}
Für dieses Ladeelement wird background
in die gewünschten Dreiecke geviertelt. Besonders ist hier auch, dass in der animation
-Anweisung unter cubic-bezier
eine Beschleunigung der Animation eingebaut wird.
.element2container {
width: 3.75rem;
height: 3.75rem; /* Maximalhöhe */
display: flex;
justify-content: center;
align-items: center; /* fixieren auf einen Punkt */
}
Da sich bei dieser Animation der Höhenabstand verändert, brauchen wir einen Container, der die maximale Größe des Elements übernimt und es auf Position hält.
<!-- Element steht im Container -->
<div class="element2container">
<div class="element2"></div>
</div>
»Ping«-Symbol
.element3 {
width: 1.25rem;
aspect-ratio: 1;
background: #FF3344;
box-shadow: 0 0 3.75rem 1rem #aa6060;
position: relative;
left: 2.5rem; /* bringt die Mitte des Elements nach rechts */
clip-path: inset(0); /* Beschneidung des Schatten-Balkens initial auf 0 */
animation: /* zwei verschiedene Animationen für Punkt und Schatten */
l4-1 0.5s ease-in-out infinite alternate,
l4-2 1s ease-in-out infinite;
}
@keyframes l4-1 {
0% {transform: translateX(-2.5rem)}
100% {transform: translateX(2.5rem)}
}
@keyframes l4-2 {
33% {clip-path: inset(0 0 0 -6.25rem)} /* ausblenden einer Seite des ›Schatten-Balkens‹ */
50% {clip-path: inset(0 0 0 0) }
83% {clip-path: inset(0 -6.25rem 0 0)} /* ausblenden der anderen Seite */
}
Dieses Symbol kann eine ausstehende Verbindung symbolisieren. Dafür werden hier Punkt und Schatten separat in @keyframe
-Anweisungen animiert. Durch clip-path
-Befehle werden dynamisch die Seiten des ›Schatten-Balkens‹ abgeschnitten.
›wartende‹ Balken
.element6 {
width: 5.25rem;
height: 3.25rem;
--g1:conic-gradient(from 90deg at left 0.2rem top 0.2rem,#FF3344 90deg,#FF3344 0);
--g2:conic-gradient(from -90deg at bottom 0.2rem right 0.2rem,#FF3344 90deg,#FF3344 0);
background:var(--g1),var(--g1),var(--g1), var(--g2),var(--g2),var(--g2);
background-position: left,center,right;
background-repeat: no-repeat;
animation: l8 1s infinite;
}
@keyframes l8 {
0% {background-size:1.5rem 50% ,1.5rem 50% ,1.5rem 50%}
25% {background-size:1.5rem 100%,1.5rem 50% ,1.5rem 50%}
50% {background-size:1.5rem 50% ,1.5rem 100%,1.5rem 50%}
75% {background-size:1.5rem 50% ,1.5rem 50% ,1.5rem 100%}
100% {background-size:1.5rem 50% ,1.5rem 50% ,1.5rem 50%}
}
Für dieses Ladeelement werden drei background
-Instanzen erstellt, die abwechselnd auf die volle Höhe vergrößert werden.
›wartende‹ Punkte
.element5 { /* dient als Container */
position: relative;
width: 6.25rem;
height: 1rem;
}
.element5:before , .element5:after{ /* generiert die zwei Kreise in linearer Bewegung */
content: "";
position: absolute;
width: 1rem;
height: 1rem;
border-radius: 50%;
background: #FF3344;
box-shadow: 2rem 0 #FF3344; /* zweiter Kreis um 2rem versetzt */
left: 0;
top: 0;
animation: ballMoveX 1s linear infinite;
}
.element5:after { /* generiert dritten Kreis, der rotiert */
box-shadow: none;
transform-origin: 2.5rem 0;
transform: rotate(-153deg);
animation: rotateLoader 1s linear infinite;
}
@keyframes rotateLoader {
0% , 10%{ transform: rotate(-153deg); }
90%, 100% { transform: rotate(0deg); }
}
@keyframes ballMoveX {
0% , 10%{ transform: translateX(0) }
90%, 100% { transform: translateX(2rem) }
}
für die Punkte wird ein interessanter CSS-Aufbau verwendet. Der ursprüngliche Klassenselektor .element5
dient nur als Container. Dafür werden die Pseudoelemente .element5:before
genutzt, um die sich linear bewegenden Punkte darzustellen und .element5:after
, um den dritten, rotierenden Punkt darzustellen. Für die Animation gibt es wieder @keyframes
.
Buffer - Ladekreis
.element1 {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
width: 3.25rem;
aspect-ratio: 1;
border-radius: 50%;
border: 0.5rem solid #FF3344;
animation:
l20-1 1.0s infinite linear alternate,
l20-2 2.0s infinite linear;
}
@keyframes l20-1{
0% {clip-path: polygon(50% 50%,0 0, 50% 0%, 50% 0%, 50% 0%, 50% 0%, 50% 0% )}
12.5% {clip-path: polygon(50% 50%,0 0, 50% 0%, 100% 0%, 100% 0%, 100% 0%, 100% 0% )}
25% {clip-path: polygon(50% 50%,0 0, 50% 0%, 100% 0%, 100% 100%, 100% 100%, 100% 100% )}
50% {clip-path: polygon(50% 50%,0 0, 50% 0%, 100% 0%, 100% 100%, 50% 100%, 0% 100% )}
62.5% {clip-path: polygon(50% 50%,100% 0, 100% 0%, 100% 0%, 100% 100%, 50% 100%, 0% 100% )}
75% {clip-path: polygon(50% 50%,100% 100%, 100% 100%, 100% 100%, 100% 100%, 50% 100%, 0% 100% )}
100% {clip-path: polygon(50% 50%,50% 100%, 50% 100%,50% 100%, 50% 100%, 50% 100%, 0% 100% )}
}
@keyframes l20-2{
0% {transform:scaleY(1) rotate(0deg)}
49.99%{transform:scaleY(1) rotate(135deg)}
50% {transform:scaleY(-1) rotate(0deg)}
100% {transform:scaleY(-1) rotate(-135deg)}
}
Auch ein klassischer Buffer-Ladekreis lässt sich ohne GIF in CSS animieren. Dafür braucht es aber eine etwas komplexe Animationen die nicht vollständig verstanden werden müssen. Im Grunde wird ein leerer Kreis erstellt mit farbiger border:
. Dann wird eine Animation mit sieben Frames implementiert, die Teile des Kreises dynamisch verdeckt. Die zweite @keyframes
-Animation lässt die erste Animation rotieren und wiederholt sie einmal.
branded Loader
.element7 {
height: 12.5rem;
width: 35rem;
border-bottom: 0.125rem solid #FF3344;
position: relative;
overflow: hidden; /* setzt ein Limit für die Sichtbarkeit der Animation */
}
.element7:before {
content: ""; /* definiert Existenz von Inhalt in :before, aber ohne Text */
position: absolute;
inset: auto 42.5% 0;
width: 3.75rem;
height: 3.75rem;
background-image: url('https://0t1.de/media/site/526e486edf-1693905327/otl.svg'); /* Grafik-Link */
background-size: contain;
background-repeat: no-repeat;
background-position: center; /* Grafik wird in das Pseudo-Element formatiert */
animation:
l1-0 1.5s cubic-bezier(0,900,1,900) infinite, /* Animationsgeschwindigkeit wird verzerrt */
l1-1 3s linear infinite;
}
@keyframes l1-0 {
0%,25% {bottom: 0%} /* springt, da der bottom des Elements vergrößert/verringert wird */
98%,to {bottom:.1%}
}
@keyframes l1-1 {
0% {translate: -500%} /* bewegt sich horizontal */
to {translate: 500%}
}
Ein persönlicher Touch kann in Momenten der Wartezeit für Sympathie sorgen. Dafür wird ein Pseudo-Element in ein umschließendes Element gesetzt. Dann lässt sich nach der Definition der Maße ein Logo via Link laden. Mit zwei @keyframes
-Animationen wird die vertikale und horizontale Bewegeung gesteuert.
Funktionaler Fortschrittsbalken
.element8 {
width: 8.75rem;
height: 1.5rem;
mask:
radial-gradient(circle closest-side,#000 94%,#0000) 0 0/20% 100%,
linear-gradient(#000 0 0) center/calc(100% - 0.75rem) calc(100% - 0.75rem) no-repeat;
background:
linear-gradient(#FF3344 0 0) 0/0% no-repeat
#ddd;
}
Ladebalken können auch verwendet werden, um den Fortschritt eines Prozesses darzustellen. Beispielsweise kann man so visuell überzeugend den Status einer Bestellung darstellen. Der Stand des Fortschrittbalkens lässt sich dann durch externe Trigger steuern. In diesem Fall wird ein einfacher Button benutzt. Es wird keine Animation benötigt, dafür aber ein JavaScript-Element, dass den Button mit dem Balken verbindet.
<script>
document.addEventListener('DOMContentLoaded', function() {
const button = document.querySelector('.button');
const progressBar = document.querySelector('.element8');
let progressState = 0;
button.addEventListener('click', function() {
// Nach Klick wird Status geupdated: 0%, 20%, 40%, 60%, 80%, 100%
progressState = (progressState + 1) % 6;
const progressPercentage = progressState * 20;
// Fortschritt wird übertragen
progressBar.style.backgroundSize = progressPercentage + '%';
});
})
</script>
Skeleton-Loader
Besonders geeignet für mobile Viewports, signalisieren Skeleton-Loader das Laden von Webseiteninhalten. Die Codelogik hier ist ähnlich simpel wie bei normalen Ladebalken und befindet sich in der anhängenden ZIP-Datei.
Da die Ladeelemente in purem CSS geschrieben sind, können sie maximal für den eigenen Usecase umgestaltet werden. Die gezeigten Ladeelemente und viele weitere können den unterstehenden Webseiten entnommen werden. Einige der Ladeelemente wurden für den Zweck dieses Blogeintrags umgestaltet und können der untenstehenden ZIP-Datei entnommen werden. Wir wünschen viel Freude beim Gestalten von Wartezeiten! :)
Links & Quellen
Links:
-https://css-loaders.com/circle/
-https://backers.webawesome.com/docs/components/progress-bar/
-https://skeleton-loader.web.app/
Quellen:
-https://www.youtube.com/watch?v=Bm_36uWbV_I
-https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction
-https://wiki.selfhtml.org/wiki/SVG/Attribut/stroke-dasharray
Codepen.io:
https://codepen.io/Nils-Siegelkow/pen/YPPRZqe
ZIP-Download: