CSS offset-path: Animation entlang eines Pfades

CSS offset-path bewegt Elemente entlang einer S-Kurve, einer Acht und schießt kleine Raketen in den Orbit. Damit wollen die Blink-Entwickler (Chrome und Opera) CSS Transition und Animationen bereichern, nachdem sie SVG SMIL-Animationen ins Abseits gesetzt haben.

CSS kennt keine Animation entlang eines Pfades: Das gibt es erst mit offset-path (zuvor Motion Path).

Das Web Animation API (WAAPI) steht als umfassende Schnittstelle für Animationen auf der Schwelle. Den ersten Vorgeschmack liefern Chrome und Opera, die das CSS Motion Path Modul aus dem Web Animation API umgesetzt haben.

Animationen sind ein bewegtes Thema. CSS-Animationen haben im Handumdrehen Karriere gemacht, Javascript-Libraries wie VelocityJs und GreenSock treten die Nachfolge von Action Script an. Aber wir haben immer noch nichts, das so handlich ist wie GIF-Animationen: Alles in einer Datei.

Das hätte mit SVG und SMIL funktioniert, hätten Blink und Microsoft die Türen nicht zugeschlagen, als SVG sich endlich entfalten konnte. Funktionsweise und Syntax von SMIL liegen abseits von CSS-Animationen und der große Erfolg der CSS-Animationen rührt nicht zuletzt in ihrer konsistenten und gut verständlichen Syntax.

Motion Path-Animationen

Die Animation von Elementen entlang eines Pfades fehlt im CSS-Animations-Angebot bislang.

Motion Path Acht für einen Flieger
Kein Support für offset-path (alte Syntax: motion-path). Versuchs mit Chrome oder Opera!

Der rote Flieger ist ein PNG-Bild, also ein HTML-Element – kein SVG. Motion Path animiert sowohl SVG- als auch HTML-Elemente mit der bekannten CSS-Syntax für Animationen.

#aero {
   offset-path: path('m 138.6,161.9 c 5.7,5.7 -4.9,10.4 -9.5,9.4 -12.3,-2.8 -14.3,-18.7 -9.3,-28.3 9,-17.2 32.1,-19.1 47.2,-9.2 22,14.4 23.9,45.6 9.1,65.9 -19.8,27.1 -59.3,29 -84.77,9.1 C 59.27,183.7 57.37,135.8 82.38,105.2 112.6,68 169,66.1 204.8,96.2 c 42.1,35.5 44,100.4 8.8,141.3 C 172.9,285 99.64,286.5 53.57,246.2 1.203,200.4 -0.5627,118.6 44.87,67.3 95.88,9.8 186.2,8.1 242.5,58.7 305.1,115 306.8,213.9 251,275.3');
   animation: acht 10s; 
}

@keyframes acht {
   0% { offset-distance: 0;}
   100% { offset-distance: 100%;}
}
offset (alte Syntax: motion)
shorthand / Kurzschrift
offset-path (alte Syntax: motion-path)
ist der Pfad, an dem das Element ausgerichtet wird. Der Pfad ist das d-Attribut eines SVG-Elements, wie er in SVG 1.1 definiert ist.
offset-distance (alte Syntax: motion-offset)
ist der Bereich des Pfades, an dem das Objekt in der Animation erscheint und wird entweder als Floating Point-Wert oder in % notiert. Mit offset-distance von 0 bis 100% läuft das Element entlang des vollständigen Pfades.
offset-rotation (alte Syntax: motion-rotation)
Ausrichtung entlang des Pfades
animation
ist die bekannte Parameter-Liste der Animation: animation-name, animation-duration, animation-delay, animation-iteration-count, und animation-timing-function (Easing).

Am Rande: Die CSS Motion Path-Eigenschaften, die bereits in Chrome installiert sind, wurden umbenannt:

  • motion-path wird offset-path
  • motion-offset wird offset-distance
  • motion-rotation wird offset-rotation

Die alte Syntax funktioniert noch in den aktuellen Versionen von Chrome, die neue Syntax in Chromium. Lt. Eric Willgers (chromium.org) wird die neue Syntax in Chrome wahrscheinlich mit dem Dezember-Release ankommen.

Motion Path in SVG

Zu den schönen Seiten von Motion Path gehört, dass wir ein Bild (wie einst ein GIF oder ein SVG mit SMIL) in einem img-Tag animieren können, ohne CSS- oder Javascript-Dateien mit Einzelteilen zu belasten. Alles schon drin …

Mit offset-path animiert
Zur Zeit schweben die Ballons nur für Chrome und Opera. Für den Rest – Safari, IE, Edge und Firefox – gibt es im Anschluss noch ein Trostplaster.
#c1 {
   offset-path: path( 'M 1169,756 C 2281,362 271,20 229,616 214,1080 56,1151 1169,757 z');
   animation: floating 40s infinite linear;
}

@keyframes floating {
   0% { offset-distance: 0%;}
   100% { offset-distance: 100%;}
}

Animation entlang eines Pfades mit SVG und SMIL

Nach der Ankündigung von Blink, dass SMIL nicht mehr erwünscht sei, traut sich kaum noch jemand, eine SVG SMIL-Animation ins Web zu setzen – obwohl die Ankündigung nicht umgesetzt wurde. Sehen wir uns die Animation entlang einer Acht trotzdem noch als SMIL animate Motion an – in Firefox, Safari, Opera oder Chrome:

<animateMotion 
      begin="0s" dur="8s" 
      rotate="auto"
      repeatCount="indefinite">
      <mpath xlink:href="#eight" />
</animateMotion>

animateMotion funktioniert ebenfalls, wenn das SVG mit einem img-Tag geladen wird, kann durch Events wie onload, onclick oder ontouch gestartet werden. Als SVG sind auch die Animationen responsive.

Am Rande: Wie wird ein Motion Path erzeugt?

XML-Editor (Shift + Ctrl + X)<svg:path id="ellipse"><svg:path id="mond"><svg:path id="path9772"><svg:path id="path9773"><svg:path id="path9792">Name Wertdm 712.1,264.4 a 310,140,5 0 0 1 -310,140,5idellipsestylefill:#c8beb7;stroke:#000;Setzendm 712.1,264.4 a 310,140,5 0 0 1 -310,140,5 310,140,5 0 01 -310,-140.5 310,140.5 0 0 1 310,-140.5 310,140.5 0 0 1310,140.5 z
Das d-Attribut eines Pfades findet man z.B. im XML-Editor von Inkscape

Adobe Photoshop CC exportiert Pfade (»Form« – nicht »Pfad«) als SVG. Genauso wie bei Inkscape oder Adobe Illustrator wird nur das d-Attribut des Pfad-Elements als Motion Path übernommen.

offset-path, offset-distance und offset-rotation agieren sowohl als pures CSS als auch via Javascript. Wie immer, wenn im CSS-Namen ein Bindestrich steht, wird es ein CamelCase.

var c1 = document.querySelector('#c1');
c1.animate([
    { offsetDistance: 0 },
    { offsetDistance: '100%' }
  ], 4000);

Restart

Per se laufen CSS-Animationen an, wenn die Seite geladen wird. Die einfachste Methode, eine Animation durch einen Klick neu zu starten: Das animierte Element klonen (mit elem.cloneNode) und das Original durch den Klon ersetzen (elem.replace).

Restart CSS Animation

Motion Path Responsive

Alles ist einfach, wenn das animierte Element in einem SVG-Element sitzt: Dann passt sich die Grafik dank viewBox-Attribut mit all ihren Elementen an den umfassenden Block an.

Wenn Motion Path HTML-Elemente animiert, übernimmt der Pfad die Maßeinheiten des Viewports als absolute Werte. Im einfachsten Fall tauscht eine Media Query den Pfad an den Breakpoints aus.

#aero { 
   offset-path: path('m 33,70.1 c 0,43 43,46 65,33 C 120,91 186.4,49.12 205,38 c 18.4,-10.6 63,-10.6 63,32.7 0,43 -45,43 -63,32.58 C 187.2,92.72 115.6,49 97.37,38.42 79,28 32.43,28 32.43,70.72 Z');
   animation: acht 10s; 
}

@media (min-width: 720px) {
   #aero { 
      offset-path: path('m 65,140 c 0,86 86,92 130,66 45,-26 178,-109 215,-130 37,-21 125,-21 125,65 0,86 -90,86 -125,65 C 374.3,183.7 231.1,96.47 194.7,75.17 158.3,53.87 64.85,53.87 64.85,139.7 Z'); 
   }
}

Pfad-Animation mit getPointAtLength und getTotalLength

Mit dem Web Animation API bekommen wir einen runden und flexiblen Nachfolger für Flash und Action Script. Bei Microsoft steht CSS Motion Path „Under consideration“. Firefox wollte der Bewegung entlang eines Pfads mit Version 48 beitreten (jetzt sind wir bei 54 … ?), bei Webkit steht ebenfalls „Under consideration“.

Es gibt ein Trostpflaster: Zwei Javascript-Methoden des Pfades steuern die Animation entlang eines Pfads.

  • getTotalLength gibt die Länge des Pfades zurück.
  • getPointAtLength gibt die x-y-Position eines Punktes auf dem Pfad zurück.
(function() { 
var p = document.createElementNS('http://www.w3.org/2000/svg','path');
p.setAttribute('d','M 746.1,57.41 C 637.5,248.8 115.7,-87.43 229.9,343.9');

var ff = document.getElementById('ff');
var head = document.getElementById('head');
head.setAttribute('transform','translate(140,220) rotate(0)');

var len = p.getTotalLength();

var ic = 0;
var repeater;
var open = 0;

function swallow () {
   var pct = ic / 250;
   var pt = p.getPointAtLength(pct * len);
   ff.setAttribute('transform','translate(' + pt.x + ',' + pt.y + ') rotate(' + ic + ')');
   if (ic > 50 && ic < 130) {
      head.setAttribute('transform','translate(140,220) rotate(' + open + ')');
      open = open - 1; 
   }
   if (ic > 210) {
      head.setAttribute('transform','translate(140,220) rotate(' + open + ')');
      open = open + 2;
   }
   ic++;
   if (ic > 250) {
      ic = 0;
      open = 0; 
   } 
   repeater = requestAnimationFrame(swallow);
}
swallow();
} () );

Animationen mit getTotalLength und getPointAtLength funktionieren in allen Browsern, die SVG unterstützen – lt. Microsoft selbst in IE9. Sie animieren nicht nur SVG, sondern auch HTML-Elemente wie Bilder und Text. Allerdings gibt getPointAtLength nur das her, was der Name besagt: einen Punkt im Koordinatensystem. Die Richtung fehlt – also keine einfache Anpassung der Ausrichtung.

Gracefully degrading

Die Alternative für Browser ohne Motion Path-Support ist … na gut … ein SVG-Standbild.

SVG-Elemente, die animiert werden, brauchen ihr eigenes Koordinatensystem. Ihr Pivot- oder Drehpunkt sitzt darum meist oben links. transform=“translate(x,y)“ schiebt ein Element auf beliebige Punkte innerhalb der viewBox. Auf die Animation hat das keinen Einfluß, aber Browser ohne Support für CSS Motion Path bekommen immerhin ein Bild serviert.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

2 Gedanken zu „CSS offset-path: Animation entlang eines Pfades“

  1. Gundi – 30. August 2016

    Da ost wirklich ein Hai in den Wolken, aber die Animation funktioniert nicht in IE oder Edge.

  2. Gerd Hennigs – 15. Juli 2016

    Ich habe den Hai in den Wolken gesehen 🙂
    Motion path ist wirklich spannend und einfach, schade dass er nur von Chrome und Opera unterstützt wird.
    Gerd (TED in Helsinki, zur Erinnerung )