Seite wählen

NETWAYS Blog

Vektorgrafiken mit CSS animieren

Nachdem SVGs (Scalable Vector Graphics) inzwischen von den meisten aktuellen Browsern recht zuverlässig unterstützt werden, findet man sie immer häufiger im Web. Die Vorteile liegen klar auf der Hand: SVGs sind auflösungsunabhängig und benötigen in der Regel weniger Speicherplatz als entsprechende Bitmap-Pendants.
Ein weiterer Vorteil: SVGs basieren nämlich (wie HTML) auf einem XML-Standard. Das heißt konkret, dass alle Elemente eines SVG-Vektorbildes (in der Regel Formen wie Kreise, Rechtecke oder Pfade) in der Datei in Form von Text beschrieben werden. Und jetzt kommt der Clou: Dadurch können ebendiese Elemente durch CSS gestyled werden und dementsprechend auch animiert werden (Das Zauberwort lautet CSS-Animationen).
Im folgenden wird in einer kleinen Case Study veranschaulicht, was beim Animieren von SVG-Vektografiken mit CSS beachtet werden muss.
Dazu erstellen wir zunächst eine SVG-Datei. Passenderweise verwenden wir in diesem Beispiel das Icinga Logo. Für den SVG-Export verwenden wir Adobe Illustrator, ebenso wäre das aber auch mit Sketch oder einem ähnlichem Vektor-sicheren Programm wie Sketch, InkScape, etc. möglich.

Vektorgrafik vorbereiten

Wir öffnen das Icinga Logo in Illustrator. Im Vorfeld muss die richtige Gruppierung der Ebenen (siehe Screenshot) berücksichtigt werden, damit man die einzelnen Elemente später gezielt ansprechen kann. Generell ist es wesentlich zeitsparender, wenn man im Vorfeld grob weiß, wie die Animation letztendlich aussehen soll.
In diesem Fall legen wir den zentralen Kreis und die einzelnen „Satelliten“ samt Ihrer Verbindungslinien auf jeweils eine Ebene. Danach gruppieren wir die Satelliten-Objekte.
Bildschirmfoto 2016-06-08 um 14.53.19

Export als SVG

Nun exportieren wir das Logo als entsprechende SVG Datei. Dies bewerkstelligen wir über Datei > Speichern unter …. Als Dateityp wählen wir SVG und aktivieren die Option Zeichenflächen verwenden. Dadurch würde bei mehreren Zeichenflächen für jede Zeichenflächen eine einzelne Datei angelegt.
Bildschirmfoto 2016-06-08 um 17.46.04

Aufbereitung des SVG-Codes

Um die einzelnen Element per CSS-Selektoren ansprechen zu können muss der SVG-Code vorbereitet werden. Dazu öffnen wir die SVG-Datei in einem Texteditor der Wahl und sehen uns den Code erst mal etwas genauer an.
Die Struktur ist recht offensichtlich: Die einzelnen Ebenen, die im Vektorgrafik-Programm angelegt wurden finden sich hier als -Elemente wieder. Die Ebenengruppen umschließen die einzelnen Ebenen mit einem -Tag. Man könnte den SVG-Code bereits so verwenden, um das ganze etwas verständlicher aufzubauen geben wir den einzelnen Elementen jeweils ein id-Attribut, damit wir diese besser ansprechen können. Der Zentrale Kreis erhält die ID primary die Satelliten benennen wir mit sat-0 … 4. Die Gruppe bekommt die id satellites.
Zum Schluss bereinigen wir den SVG-Code noch und entfernen die fill-Attribute. Diese fügen wir später im CSS wieder ein.
Hier wäre der fertige SVG-Code:

<svg>
<g id="icinga-logo">
<g id="satellites">
 <path
   id="sat-0"
   d="M70.9,0C64,0,58.4,5.6,58.4,12.5c0,4.2,2.1,7.9,5.3,10.2L43.3,64.8l3.8,1.8l20.4-42.1c1.1,0.3,2.3,0.5,3.5,0.5c6.9,0,12.5-5.6,12.5-12.5S77.8,0,70.9,0z"
 />
 <path
   id="sat-1" d="M112.6,37.5c-4.6,0-8.3,3.7-8.3,8.4c0,0.1,0,0.2,0,0.3L44.6,63.7l1.2,4l59.7-17.6c1.5,2.4,4.1,4.1,7.2,4.1c4.6,0,8.3-3.7,8.3-8.4C120.9,41.2,117.2,37.5,112.6,37.5z"
 />
 <path
   id="sat-2"
   d="M68.8,95.9c-0.5,0-1,0.1-1.5,0.2L46.9,64.6l-3.5,2.3l20.4,31.4c-0.8,1.1-1.3,2.4-1.3,3.8c0,3.4,2.8,6.3,6.2,6.3c3.5,0,6.3-2.8,6.3-6.3C75,98.6,72.2,95.9,68.8,95.9z"
 />
 <path
   id="sat-3"
   d="M21.3,103.6l25.6-36.7l-3.4-2.4l-25.6,36.7c-1.6-0.8-3.4-1.2-5.3-1.2C5.6,100,0,105.6,0,112.6c0,6.9,5.6,12.5,12.5,12.5c6.9,0,12.5-5.6,12.5-12.5C25,109.1,23.6,105.9,21.3,103.6z"
 />
 <path
   id="sat-4"
   d="M45.7,63.5l2.7-3.2L20.1,36.9c0.5-1.1,0.8-2.3,0.8-3.5c0-4.6-3.7-8.4-8.3-8.3c-4.6,0-8.3,3.7-8.3,8.3c0,4.6,3.7,8.4,8.3,8.3c1.8,0,3.5-0.6,4.9-1.6L45.7,63.5z"
 />
</g>
 <path
   id="primary"
   d="M31.8,46c9.5-7.7,23.4-6.3,31.1,3.2c7.7,9.4,6.3,23.4-3.2,31.1c-9.5,7.7-23.4,6.3-31.1-3.2C20.9,67.7,22.3,53.7,31.8,46z"
 />
</g>
</svg>

 
Jetzt wollen wir die SVG-Datei in unser HTML einbinden. Grundsätzlich gibt es zwei Möglichkeiten, SVGs mit entsprechendem CSS anzulegen.

1. Inline SVG direkt im HTML einbinden

Im HTML wird der SVG Code innerhalb eines -Tags direkt in die HTML-Datei eingebunden. Dadurch können die einzelnen Elemente direkt mit Inline-Styles oder über ein externes CSS-File wie gewohnt angesprochen werden. Diese Variante ermöglicht außerdem, die  <svg>-Elemente per Javascript zu manipulieren.

2. SVG in eine separate Datei auslagern und per <img>-Tag oder als CSS-Background einbinden

Möchte man das animierte SVG an mehreren Stellen einbinden, ist es sinnvoll den SVG-Code samt Styleangaben in eine separate Datei auszulagern. Diese .svg Datei kann dann wie gewohnt per <img>-Tag oder CSS-Background eingebunden werden. Leider ist es in dieser Variante nicht möglich die Elemente per Javascript anzusteuern und entsprechend zu manipulieren.
Der Einfachheit halber wird in diesem Beispiel Variante 1 gewählt

Animation des zentralen Kreiselements

Nun kann es los gehen. Zunächst definieren wir eine Animation in unserem CSS mit @keyframes. Hier sollte beachtet werden, dass in diesem Beitrag der Übersichtlichkeit wegen keine Vendor-Prefixes berücksichtigt werden.

@keyframes primaryPulse {
  from { transform: scale(1) }
  to   { transform: scale(1.1) }
}

Diese Animation weisen wir dem mittleren Kreiselement mit der id primary zu und vergeben eine Dauer von 3 Sekunden in der die Animation abgespielt werden soll. Wichtig ist in diesem Fall den transform-origin anzugeben.

#primary {
  animation-name: primaryPulse;
  animation-duration: 3s;
  transform-origin: center center;
}

Die Animation wird dadurch einmal abgespielt. Um die Animation dauerhaft abzuspielen erweitern wir die CSS-Angaben mit animation-iteration-count. Dadurch würde die Animation abspielen und am Ende wieder abrupt zum Anfang zu springen. Das ergäbe einen unschönen Sprungeffekt. Um einen pulsierenden Effekt zu erzielen vergeben wir zusätzlich noch die animation-direction Eigenschaft. Somit wird die Animation abwechselnd vorwärts und rückwärts abgespielt.

#primary {
  animation-name: primaryPulse;
  animation-duration: 3s;
  transform-origin: center center;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

 

Bewegung für die Satelliten

Nun wollen wir den Satelliten etwas Leben einhauchen und auch diese animieren. Diese sollen einen leichten Rotationseffekt erhalten, der wie beim zentralen Kreis alternierend abgespielt werden soll. Dadurch definieren wir zunächst wieder die Animation über @keyframes.

@keyframes rotate {
  from { transform: rotate(-3deg) }
  to   { transform: rotate(3deg) }
}

Wir weisen den einzelnen Satelliten-Elementen die Animation zu. Über animation-delay erzielen wir, dass die Satelliten-Animation leicht versetzt startet. Dadurch wird vermieden, dass die Animation zu synchron abläuft und zu mechanisch wirkt. Wichtig hierbei ist auch die entsprechende Angabe der transform-origin Eigenschaft, damit die Satelliten um die Mitte des Logos rotieren.

#sat-0 {
  transform-origin: bottom left;
  animation-name: rotate;
}
#sat-1 {
  transform-origin: bottom left;
  animation-name: rotate;
  animation-delay: 1.5s;
  animation-duration: 6s;
}
#sat-2 {
  transform-origin: top left;
  animation-name: rotate;
  animation-delay: 3s;
  animation-duration: 6s;
}
#sat-3 {
  transform-origin: top right;
  animation-name: rotate;
  animation-duration: 6s;
}
#sat-4 {
  transform-origin: bottom right;
  animation-name: rotate;
  animation-delay: 3s;
  animation-duration: 6s;
}

Um den Code schlank zu halten, verwenden wir die CSS Selektoren und wählen alle <path>-Elemente der #satellite Gruppe aus. Hier setzen wir alle Eigenschaften, die für alle Satelliten-Elemente nötig sind.

#satellites > path {
  animation-duration: 3s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

Zu guter letzt erstellen wir noch eine Animation für die gesamte Satellitengruppe um die Logoanimation noch etwas organischer zu machen …

@keyframes globalPulse {
  from { transform: scale(1) }
  to   { transform: scale(1.2) }
}

… und weisen diese der #satellites-Gruppe zu

#satellites {
  animation-name: globalPulse;
  animation-duration: 10s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  transform-origin: center center;
}

 

Und so sieht die Animation aus

See the Pen RRWmay by Florian Strohmaier (@flourish86) on CodePen.

Florian Strohmaier
Florian Strohmaier
Senior UX Designer

Mit seinen Spezialgebieten UI-Konzeption, Prototyping und Frontendentwicklung unterstützt Florian das Dev-Team bei NETWAYS. Trotz seines Design-Backgrounds fühlt er sich auch in der Technik zuhause. Gerade die Kombination aus beidem hat für ihn einen besonderen Reiz.

Fronted-Performance optimieren in Chrome – Like a Boss

Nicht nur Frontend Entwickler kennen es: Man freut sich, dass die hollywoodreifen Animationen auf der Webseite oder im User Interface endlich funktionieren. Ein raffinierter Parallax-Effekt verleiht dem Ganzen dann noch den letzten Schliff. Das Problem: Es ruckelt und hakt an allen Enden, die Lüfter seines nagelneuen Rechners fangen an zu drehen. Was tun?
Zum Glück bieten die Chrome-Developer Tools einige hilfreiche Werkzeuge an, um die Performancefresser zu identifizieren. Diese geben nicht nur einen guten Überblick über Performance-Engpässe sondern dokumentieren außerdem die Bildwiederholrate, CPU-Auslastung und das Asset-Handling.

Wo finde ich diese Tools nun?

Wer die Chrome Developer-Tools kennt, ist möglicherweise schon mal über das Timeline Tab gestolpert. Öffnet man die Ansicht das erste Mal, ist es nicht ganz unwahrscheinlich, dass man von der hohen Informationsdichte erschlagen ist. Daher soll dieser Artikel als eine Art Entry-Point für den Einstieg sein. Denn es lohnt sich.
Ist das Timeline-Tab bereits geöffnet und die Seite wird neu geladen, werden die Performance-Daten des initialen Seitenaufrufes bis zum fertigen Rendern der Seite automatisch aufgezeichnet.
Danach kann man einzelne Aufzeichnungen starten, um z.B. die Performance einzelner Interaktionen auf der Seite untersuchen zu können. Dabei sollte beachtet werden: Je kürzer die Aufnahme und je weniger Aktionen aufgezeichnet werden, desto einfacher ist die Analyse.

Überblick

Der Einstieg: Ein kurzer Überblick über die Oberfläche.
Bildschirmfoto 2016-03-30 um 13.07.21

A) Bedienelemente

Die beiden linken Symbole dienen zum Starten und Stoppen der Aufzeichnung. Alternativ kann hierfür das Tastenkürzel cmd + E / Strg + E verwendet werden. Mit den Checkboxen können zusätzliche Informationen an/abgewählt werden, die dann entsprechend mit aufgezeichnet werden.

B) Überblick

Diese Ansicht bietet eine Übersicht über den Verlauf der Seiten-Performance. Sie dient außerdem als Navigation, um den aktuellen Bereich auszuwählen.

C) Flame-Chart

Hier werden die einzelnen Ereignisse und deren Dauer als horizontale Balken visualisiert. Parallele Ereignisse werden nach unten gestapelt. Der findige Beobachter erkennt hier drei unterschiedliche gefärbte vertikale gestrichelte Linien: die blaue Line stellt den DOMContentLoaded-Event dar. Die grüne Linie markiert den ersten Paint-Event und die rote den load Event.

D) Details

Ist kein Ereignis angewählt werden hier die Statistiken für  Zeitraum aufgeführt, der in der Übersichtsansicht ausgewählt ist. Um die Anzeige auf ein Ereignis zu begrenzen, kann im Flame-Chart ein Ereignis ausgewählt werden.
In der Überblicksansicht kann man die Auswahl der Ereignisse eingrenzen in dem man die Regler verschiebt. Die Visualisierungen im Flame-Chart und dem Detailbereich passen sich entsprechend an und beziehen sich nur auf den ausgewählten Bereich.
2016-03-30 16_25_29

Exkurs: Die typische Rendering-Pipeline

In der Regel gibt es fünf verschiedene Schritte bei der Frame-Berechnung, die bei der Entwicklung zu beachten sind. Über diese Bereiche hat  der Entwickler die größte Kontrolle.

Javascript

Typischerweise werden Scriptaufrufe verwendet um Werte zu ändern, die dann in Änderungen der Darstellung resultieren. Das kann z.B. die animate Funktion in jQuery sein oder das Hinzufügen von DOM-Elementen. Diese Darstellungsänderungen werden nicht ausschließlich durch Javascript ausgelöst. Es können auch CSS-Animationen, Transistions, o.ä. dafür verantwortlich sein.

Style Calculations

In diesem Prozess findet der Browser heraus, welche CSS-Regeln anhand der Style-Angaben für welche Elemente angewandt werden müssen.

Layout

Darauf folgt in der üblicherweise die Berechnung der Positionen der jeweiligen Elemente und wie viel Platz diese benötigen. Das Layout-Modell des Webs ist so konzipiert, dass gewisse Abhängigkeiten der Elemente untereinander herrschen. Verändert ein Element, welches mit float positioniert ist seine Breite, beeinflusst es die Position und Größe der umliegenden Elemente.

Paint

Im Painting-Prozess werden die Pixel der einzelnen Elemente berechnet. Es berücksichtigt Eigenschaften wie Text, Farben, Bilder, Rahmen. Die Berechnung findet auf verschiedenen Ebenen (Layers) statt.

Composite

Nachdem Painting-Prozess sind die einzelnen Komponenten (Layers) der Seite bereits berechnet. Beim Compositing werden diese Komponenten dann übereinander gelegt. Besonders entscheidend ist dies bei überlappenden Elementen.

1. JS/CSS >Style > Layout > Paint > Composite

Pasted Graphic
Wenn eine Eigenschaft eines Elements verändert wird, welche dessen Abmessungen oder Position verändert (z.B. height, width, top, left, o.ä, muss der Browser alle oder zumindest alle umliegenden Elemente neu berechnen und zusammengesetzt werden (Layout > Paint > Composite)

2. JS/CSS > Style > Paint > Composite

Pasted Graphic 1

Werden nur Paint-only Eigenschaften geändert (background-image, color, box-shadow), kann der Browser den Layout-Prozess überspringen.

3. JS/CSS > Style > Composite

Pasted Graphic 2

Wenn eine Eigenschaft verändert wird, bei denen der Layout und Painting-Prozess übersprungen werden kann, überspringt der Browser diese Schritte und springt direkt in den Compositiing-Prozess. Darunter fallen z.B. transform oder opacity.
Vor allem für performance-kritische Fälle, z.B. für Animationen oder bei Scroll-Events, bei denen die entsprechenden Funktionen in der Regel besonders oft aufgerufen werden, ist diese Variante besonders erstrebenswert.

Repaintbereiche auf der Seite visualisieren

Im DevTools Hauptmenü gibt es einen Eintrag mit der Bezeichnung More Tools nennt. Wählt man hier die Rendering Settings aus, erhält man weitere Funktionen. Ist die zusätzliche Leiste am unteren Bildschirmrand nicht sichtbar, kann man diese mit der Esc-Taste wieder erscheinen lassen.
Im Teilfenster am unteren Bildschirmrand befindet sich dann eine Check-Box mit dem Titel Enable paint flashing.

rendering-settings

Über das DevTools Hauptmenü können weitere Tools eingeblendet werden.


Aktiviert man diese werden auf der Seite Bereiche markiert, bei denen Painting-Events auftreten. So erhält man in Echtzeit einen guten Überblick, welche Bereiche für mögliche Performance-Engpässe sorgen.
2016-03-30 22_26_11
————
Es gibt einen Talk von Paul Irish, der mehrere Anwendungsbeispiele veranschaulicht.

Florian Strohmaier
Florian Strohmaier
Senior UX Designer

Mit seinen Spezialgebieten UI-Konzeption, Prototyping und Frontendentwicklung unterstützt Florian das Dev-Team bei NETWAYS. Trotz seines Design-Backgrounds fühlt er sich auch in der Technik zuhause. Gerade die Kombination aus beidem hat für ihn einen besonderen Reiz.

CSS3-Transitions

Seit CSS3 bietet die Stylesheet-Sprache die Möglichkeit von Überblendungen von CSS-Eigenschaften, wenn sich dieser beispielsweise durch einem Mouseover ändert oder per Javascript geändert wird.
Dabei wird der Übergang vom Startwert zum Zielwert über eine Zeitspanne interpoliert, es entsteht eine Animation.
Für das Erstellen von CSS-Transitions, müssen zwei Werte angegeben werden: Die Dauer für den Übergang und das CSS-Property auf die die Transition angewandt werden soll.

.element {
  transition: [transition-property] [transition-duration] [transition-timing-function] [transition-delay];
}

 
Der Übergangs-Effekt wird gestartet, sobald sich der Wert ändert.

.element:hover {
  width: 300px;
}

 
Es ist auch möglich, einen transition-Effekt für mehrere Werte anzugeben.

.element {
  transition: width 2s, height 4s;
}

 
Setzt man für transition-property den Wert all, werden Transitions für alle möglichen Werte definiert.

.element {
  transition: all 2s;
}

 

Parameter

 

transitiv Eine Abkürzung für alle Parameter
transition-delay Gibt in Millisekunden (ohne Angabe, z. B. 500) an, wie lange es dauert bis die Animation nach der Änderung des Wertes startet. . Es können auch Sekunden angegeben werden (z. B. 0.5s)
transition-duration Legt fest, wie lange die Animation in Millisekunden dauert.
transition-property Definiert, für welche CSS-Eigenschaften Transitions erstellt werden.
transition-timing-function Über diese Angabe, kann das Timing der Animation festgelegt werden.

 

Delay

Über transition-delay erhält die Transition eine Verzögerung, d.h. die Animation startet entsprechend später.
Hier zum Vergleich eine Demo zu transition-delay.

 

Timing

Das Timing bestimmt, die Funktion, mit der die Werte interpoliert werden. Dadurch kann man die Dynamik der Transition beeinflussen. Hier die Werte für die Timing-Funktion:

linear Lineare Interpolation, d.h. der Übergang geht mit gleichbleibender Geschwindigkeit von statten. Dies wirkt in der Praxis sehr mechanisch und unnatürlich.
ease langsamer Start, schneller und langsames Ende. Dies ist die dynamischste der vorgegebenen Funktionen. Der Übergang wirkt dynamisch und natürlich. Dies wird standardmäßig verwendet.
ease-in Langsamer Start.
ease-out Langsames Ende
esse-in-out Wie ease, nur etwas gleichmäßiger. Wirkt natürlich, aber gleichmäßiger als ease.
cubic-bezier(n,n,n,n) Mit diesem Wert kann kubische Bezier-Funktionen verwenden, um das Timing zu definieren. Damit lassen sich beispielsweise Bounce-Effekte erzielen.

 
Hier eine kurze Demo der einzelnen Timingfunktionen im Vergleich:

Probleme

 
Leider kann man Transitions mit dem Wert auto nicht vernünftig einsetzen. In der Praxis würde man dies beispielsweise für einen Akkordion-Effekt verwenden, bei der der Inhalt der einzelnen Container variabel ist. Leider ist die Implementierung nicht wie erwartet, der Wert springt zwischendrin auf 0 und nimmt dann ruckartig den automatisch berechneten Wert an. Dieses Problem kann leider nur mit Javascript gelöst werden, in dem man die Höhe des Inhalts berechnet und explizit angibt.

 

Browserkompatibilität

 

Bildschirmfoto 2016-02-22 um 16.01.04

Abb. 1: CSS-Transitions werden von modernen Browsern bereits unterstützt. Für ältere Versionen empfiehlt sich die Verwendung von Browser-Prefixes.


Eine Übersicht von caniuse.com zeigt, dass CSS Transition bereits gut unterstützt werden. Problem macht der Internet Explorer ab einschließlich Version 9 abwärts. Allerdings lassen sich Transitions sehr gut für einen Progressive-Enhancement-Ansatz verwenden. Da nicht unterstützende Browser die transition Angaben einfach ignorieren, kann man diese getrost verwenden. Es macht aber Sinn die Angaben mit Browser-Prefixes zu versehen, da nicht ganz aktuelle Versionen von Firefox, Safari oder Chrome die Eigenschaft nicht ohne unterstützen.
 
 

Florian Strohmaier
Florian Strohmaier
Senior UX Designer

Mit seinen Spezialgebieten UI-Konzeption, Prototyping und Frontendentwicklung unterstützt Florian das Dev-Team bei NETWAYS. Trotz seines Design-Backgrounds fühlt er sich auch in der Technik zuhause. Gerade die Kombination aus beidem hat für ihn einen besonderen Reiz.