SVG mit CSS animieren

Ladeanimation selbst gemacht

Inline-SVG-Grafiken kann man mit CSS ganz wundervoll animieren. Auf diese Art habe ich aus meinem Webseitenlogo eine Ladeanimation gebastelt.

von Christian

Meine Seite ist seit dem Relaunch (Oktober 2022) in einigen Teilen (christliche Lieder, off-Beats) hochdynamisch.
Beim Scrollen werden Inhalte nachgeladen. Links werden automatisch aufgelöst und die Seiteninhalte im Hintergrund dynamisch per asynchronem Request angefragt.
Und Bilder werden erst bei Bedarf geladen sobald sie im sichtbaren Bereich der Seite sind (Lazy-Loading).

Insbesondere bei Seiten mit großen Bildern oder anderen Medien kann die Serverabfrage im Hintergrund etwas länger dauern.
Um diese Wartezeiten etwas zu verkürzen, habe ich mein Logo animiert und als Ladeanimation eingebaut:

Lädt …

Das Besondere an dieser Animation ist, dass das Logo eine einfache SVG-Datei ist, welche mittels einer CSS-Animation animiert wird.

Eine animierbare SVG-Datei selber machen

Damit die SVG animiert werden kann, müssen die einzelnen Kurven/Pfade (Kopf, Linke Seite, Rechte Seite, Oberer Strich, Unterer Strich) gruppiert und benannt werden.

Das sieht dann im Quelltext etwa so aus:

<svg class="logo" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="421.955" height="376.947" baseProfile="tiny" viewBox="0 0 421.955 376.947">
    <linearGradient id="logo__head" x1="11.2729" x2="413.0973" y1="214.0815" y2="-17.9118" gradientUnits="userSpaceOnUse">
        <stop offset="0" stop-color="#245526" />
        <stop offset=".8848" stop-color="#569b32" />
    </linearGradient>
    <linearGradient id="logo__left" x1="24.2959" x2="421.9125" y1="238.2427" y2="8.6786" gradientUnits="userSpaceOnUse">
        <stop offset="0" stop-color="#245526" />
        <stop offset=".8848" stop-color="#569b32" />
    </linearGradient>
    <linearGradient id="logo__right" x1="66.0098" x2="462.4214" y1="306.5444" y2="77.6761" gradientUnits="userSpaceOnUse">
        <stop offset="0" stop-color="#245526" />
        <stop offset=".8848" stop-color="#569b32" />
    </linearGradient>
    <linearGradient id="logo__top" x1="38.4873" x2="432.6734" y1="282.6987" y2="55.1153" gradientUnits="userSpaceOnUse">
        <stop offset="0" stop-color="#245526" />
        <stop offset=".8848" stop-color="#569b32" />
    </linearGradient>
    <linearGradient id="logo__bottom" x1="58.6123" x2="470.2382" y1="316.8208" y2="79.1685" gradientUnits="userSpaceOnUse">
        <stop offset="0" stop-color="#245526" />
        <stop offset=".8848" stop-color="#569b32" />
    </linearGradient>
    
    <g class="logo__group">
        <circle class="logo__head" cx="223.508" cy="91.547" r="33.06" fill="url(#logo__head)" />
        <path 
        	class="logo__left" 
        	fill="url(#logo__left)"
            d="m80.456 376.947 1.915-3.982c.625-1.297 1.433-2.881 2.314-4.771.86-1.9 1.874-4.066 3.019-6.479 2.232-4.863 4.834-10.82 ... 3.606-2.554 3.606z"
        />
        <path
            class="logo__right"
            fill="url(#logo__right)"
            d="m149.955 360.947 1.086-5.074c.688-3.311 1.874-8.133 3.528-14.264.886-3.041 1.865-6.408 2.933-10.074 1.142-3.643 ... 4.867-1.799 4.867z"
        />
        <path
            class="logo__top"
            fill="url(#logo__top)"
            d="M26.376 243.902s1.027-.852 2.954-2.445c.967-.792 2.161-1.763 3.593-2.88 1.425-1.124 3.062-2.431 4.945-3.806 3.745-2.791 ... 1.831-3.371 1.831z"
        />
        <path
            class="logo__bottom"
            fill="url(#logo__bottom)"
            d="M0 325.962s1.015-.854 2.916-2.457c1.922-1.572 4.698-3.941 8.323-6.826 3.616-2.9 7.987-6.451 13.104-10.389 5.1-3.963 ...  325.962 0 325.962z"
        />
    </g>
</svg>

Zuerst wird die SVG-Datei definiert (Z. 1). Ich habe gute Erfahrungen gemacht, sowohl eine width und height als auch eine viewBox anzugeben.

Anschließend werden Gradienten, also Farbverläufe, definiert (Z. 2-21). Damit man die jeweiligen linearGradient hinterher auch ansprechen kann, erhalten sie eine ID (z.B. id="logo__head" oder id="logo__left".
Wenn du einfarbige Pfade hast, dann kannst du diese Gradienten auch einfach weglassen (oder später mit CSS einfärben).

Als nächstes folgt eine Gruppe <g class="logo__group">, in der sich alle einzelnen Pfade befinden.

Der "Kopf" des Logos ist sehr schnell mit einem <circle class="logo__head"> definiert und wird per fill="url(#logo__head)" mit dem entsprechenden Gradienten verknüpft.

Die anderen Teile des Logos sind Pfade mit längeren Koordinatenangaben (und wurden im Codebeispiel deutlich gekürzt). Aber auch hier wird wieder eine Klasse vergeben (class="logo__right") und ein Gradient verknüpft (fill="url(#logo__left)").

Dann ist die SVG schon beinahe fertig.

Um auf die "klassifizierten" Elemente per CSS zugreifen zu können, muss die SVG auf der HTML-Seite direkt inline im Quelltext eingebunden werden. Und damit das auch dynamisch tadellos funktioniert, sollte die Datei über einen einfachen SVG-Minifyer im Internet noch komprimiert werden.
Insbesondere wenn ich die Grafik über Javascript reinlade, (um sie dynamisch in der Contao-Erweiterung Infinite Scroll zu einzubinden) sollten keine Zeilenumbrüche mehr vorhanden sein.

Animation des Logos mit CSS

Die CSS-Animation ist auch gar nicht so kompliziert.

Sie besteht einmal aus den CSS-Befehlen, welche das Logo stylen, positionieren, und die zu verwendende CSS-Animation zuweisen: animation: logo-head 3.5s 0.5s infinite forwards linear;

.loader {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    opacity: 1;
    background: #fff;
    z-index: 6000;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    flex-direction: column;
}
.loader__container {
    pointer-events: none;
    max-width: 80vw;
    max-height: 80vw;
    border-radius: 100%;
    width: 120px;
    height: 120px;
}
.loader .logo {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
}
.loader .logo circle,
.loader .logo g,
.loader .logo path {
    transform-origin: 50% 50%;
    transform-box: fill-box;
}
.loader .logo .logo__head {
    animation: logo-head 3.5s 0.5s infinite forwards linear;
}
.loader .logo .logo__left {
    animation: logo-left 3.5s 0.5s infinite forwards linear;
}
.loader .logo .logo__right {
    animation: logo-right 3.5s 0.5s infinite forwards linear;
}
.loader .logo .logo__top {
    animation: logo-top 3.5s 0.5s infinite forwards linear;
}
.loader .logo .logo__bottom {
    animation: logo-bottom 3.5s 0.5s infinite forwards linear;
}
.loader__message {
    margin: 20px;
}

Und dann besteht die CSS-Animation natürlich noch aus den Keyframes, welche sie definieren und die Bewegung der einzelnen Elemente bestimmen.

In den Keyframes wird im Zeitverlauf der Animation (von 0% zu 100%) festgelegt, dass z.B. die Transparenz sich ändert (opacity:1), und wie das einzelne Element mit einer Transformation/Skalierung von der Seite aus reinfährt: transform: scale(1.2, 0.8) translateX(-500%);


Es gibt noch eine kleine Besonderheit:

Da diese Ladeanimation in der Regel nur Bruchteile einer Sekunde angezeigt wird, beginne ich die Animation direkt mit einem fertig aufgebauten Logo (bei 0%).
Dieses Logo wird dann im Verlauf der Animation erst einmal ausgeblendet (8%- 29%) und anschließend beginnt erst das Reinfahren der Elemente an die finale Position (30-100%).

Die komplexeste Animation ist dabei der Bounce-Effekt des Kopfes, der von oben reinfällt und 2-3 mal leicht zurückfedert.
Aber insgesamt ist auch das kein Hexenwerk:

@keyframes logo-bottom {
    8% {
        opacity: 1;
    }
    20%,
    29% {
        opacity: 0;
        transform: scale(1, 1) translateX(0);
    }
    30% {
        opacity: 0;
    }
    31% {
        opacity: 1;
        transform: scale(1.2, 0.8) translateX(-500%);
    }
    50% {
        transform: scale(1, 1) translateX(0);
    }
}
@keyframes logo-top {
    5% {
        opacity: 1;
    }
    20%,
    29% {
        opacity: 0;
        transform: scale(1, 1) translateX(0);
    }
    30% {
        opacity: 0;
    }
    31%,
    38% {
        opacity: 1;
        transform: scale(1.2, 0.8) translateX(-500%);
    }
    50% {
        transform: scale(1, 1) translateX(0);
    }
}
@keyframes logo-left {
    5% {
        opacity: 1;
    }
    25%,
    29% {
        opacity: 0;
        transform: scale(1, 1) translate(0, 0);
    }
    30% {
        opacity: 0;
    }
    31%,
    35% {
        opacity: 1;
        transform: scale(0.5, 0.8) translate(-900%, 300%);
    }
    62% {
        transform: scale(1, 1) translate(0, 0);
    }
}
@keyframes logo-right {
    8% {
        opacity: 1;
    }
    25%,
    29% {
        opacity: 0;
        transform: scale(1, 1) translate(0, 0);
    }
    30% {
        opacity: 0;
    }
    31%,
    40% {
        opacity: 1;
        transform: scale(0.5, 0.8) translate(-350%, 300%);
    }
    62% {
        transform: scale(1, 1) translate(0, 0);
    }
}
@keyframes logo-head {
    17% {
        opacity: 1;
    }
    28%,
    29% {
        opacity: 0;
        transform: scale(1, 1) translateY(0);
    }
    30% {
        opacity: 0;
        transform: scale(0.9, 1.1) translateY(-300%);
    }
    31%,
    65% {
        opacity: 1;
        transform: scale(0.9, 1.1) translateY(-300%);
    }
    100%,
    70%,
    78%,
    86% {
        transform: scale(1, 1) translateY(0);
    }
    73% {
        transform: scale(1.05, 0.95) translateY(-70%);
    }
    82% {
        transform: scale(1.02, 0.97) translateY(-30%);
    }
}

Um sicherzustellen, dass die Ladeanimation direkt beim Beginn des Seitenaufrufs angezeigt wird, sollte auch der CSS-Code inline im HTML-Quelltext stehen.

Wenn man den CSS-Code erst über eine ausgelagerte CSS-Datei nachladen müsste, könnte währenddessen die Animation noch nicht ablaufen.
Und das ist ja nicht ganz der Sinn der Sache, oder?

 

Und am Ende sieht die CSS-Animation der SVG-Datei dann so aus:

Lädt …

 

Was hältst du von dieser Animation und diesem Tutorial?

Reichen dir diese Infos, um die Animation selbst nachzubauen? Oder möchtest du noch ein Follow-Up zu dem rotierenden Kreis, oder wie die Animation die gesamte Seite überlagert und beim Abschluss des Ladevorgangs verblasst?

Schreib's mir in die Kommentare!

  Zurück zur Newsübersicht

Einen Kommentar schreiben

Bitte rechnen Sie 3 plus 5.

Kommentare

1) Kommentar von Agonyz

Das muss ich mir mal genauer ansehen und bei meinem Projekt umsetzen :)

Weitere Beiträge

von Christian

Music-XML-Konverter

Text und Akkorde aus MusicXML-Dateien extrahieren

MusicXML ist ein Standard-Austausch-Format zwischen den Notationsprogrammen. Mit diesem Konverter lassen sich LeadSheets als ChordPro extrahieren.

Weiterlesen …

von Christian

Web-Konverter für Chord-Pro

Chord-Pro in Akkorde mit Lyrics umschreiben

Das Chord-Pro-Format ist enorm praktisch und universell nutzbar. Besser lesbar ist aber das "Akkord-über-Liedtext" Format.
Mit diesem Konverter lassen sich sehr einfach aus Chord-Pro klassische Lyrics generieren.

Weiterlesen …

von Christian

SVG mit CSS animieren

Ladeanimation selbst gemacht

Inline-SVG-Grafiken kann man mit CSS ganz wundervoll animieren. Auf diese Art habe ich aus meinem Webseitenlogo eine Ladeanimation gebastelt.

Weiterlesen …

von Christian

mein größtes Programmierprojekt

Das Spruch-Archiv

Von einem Spaßprojekt ist das Spruch-Archiv zu einer der größten Spruch-Plattformen im Internet gewachsen. Dies ist die Entstehungsgeschichte.

Weiterlesen …

von Christian

Spam im Mailpostfach

Eine neue Phishing-Mail

Eine hochgefährliche Mail mit einer als Bild getarnten PHP-Datei hat mich erreicht. Zum Glück wurde das Bilder-Nachladen durch Thunderbird automatisch verhindert.

Weiterlesen …

von Christian

Datenschutzverstöße und E-Mail-Spam

Dienste, die beschissen mit meiner Mail-Adresse umgehen

Diese Dienstleister haben nachweislich meine E-Mail-Adresse "verloren". Leider zeigen sich viele uneinsichtig und schieben die Verantwortung von sich.

Weiterlesen …

von Christian

Fehlerhafte Thunderbird-Erweiterung

Thunderbird 31.4.0 stürzt nach Update ab

Die Erweiterung "Show Address Only" sorgt bei der Thunderbird-Version 31.4.0 (2015) dafür, dass das E-Mail-Programm abstürzt und nicht mehr startet.

Weiterlesen …

von Christian

Contao-Erweiterung

Contao: Facebook Like-Button asynchron und valide

Eine Möglichkeit, um den Facebook-Like-Button valide in Contao einzubinden und asynchron laden zu lassen.

Weiterlesen …

von Christian

Feiert Jesus! 1-4: Komplettes Inhaltsverzeichnis

Ein komplettes, kompaktes Inhaltsverzeichnis der Feiert-Jesus-Bände 1-4 als Excel und PDF.

Weiterlesen …

von Christian

Winter-Einsamkeits-Mutmachlied

Eigentlich okay

Als spontane Auftragskomposition entstand eines meiner Lieblingslieder über Einsamkeit und Akzeptanz.

Weiterlesen …

von Christian

Hassgedicht auf den Herbst

Mein Herbstgedicht

Meine Mitwirkung an "Bayerns längstem Herbstgedicht" war vielen wohl zu negativ "eingefärbt" und wurde zensiert.

Weiterlesen …

von Christian

Endlich ein Stagepiano

Neues E-Piano - Neuer off-Beat: Hearts

Nach reiflichen Überlegungen habe ich mir endlich ein Stage-Piano von Kawai geleistet.

Weiterlesen …