SVG mit CSS animieren: Ladeanimation selbst gemacht
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:
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:
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!
Weitere Beiträge
Hassgedicht auf den Herbst: Mein Herbstgedicht
Meine Mitwirkung an "Bayerns längstem Herbstgedicht" war vielen wohl zu negativ "eingefärbt" und wurde zensiert.
Endlich ein Stagepiano: Neues E-Piano - Neuer off-Beat: Hearts
Nach reiflichen Überlegungen habe ich mir endlich ein Stage-Piano von Kawai geleistet.
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.
Einen Kommentar schreiben
Kommentare
1) Kommentar von Agonyz
Das muss ich mir mal genauer ansehen und bei meinem Projekt umsetzen :)