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

0%
<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

0%
<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

0%
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 oder circle)

  • Fortschritt wird meist per width (div) oder strokeDashoffset (SVG) gesteuert

  • JavaScript 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://cssloaders.github.io

-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:

ladeelemente-in-css.zip


© 0t1

Cookies

0t1 mag keine Kekse (und kein Tracking). Wir verwenden lediglich notwendige Cookies für essentielle Funktionen.

Wir verwenden Schriftarten von Adobe Fonts. Dafür stellt dein Browser eine Verbindung zu den Servern von Adobe in den USA her. Wenn du unsere Seite nutzen möchtest, musst du dich damit einverstanden erklären.

Weitere Informationen in unserer Datenschutzerklärung.