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 4 plus 1.

Kommentare

1) Kommentar von Agonyz

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

Weitere Beiträge

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 …

von Christian

Katzenbesuch

Ne hübsche Mieze im Bett

Ich habe einen kleinen Kater auf der Straße gefunden... und natürlich direkt eingesammelt. Mittlerweile ist er wieder wohlbehalten zurück bei seiner Familie.

Weiterlesen …