CSS Animation entlang eines Pfades: offset-path

CSS offset-path bewegt Elemente entlang eines Pfads: einer S-Kurve, einer Acht oder beliebiger Formen und schießt kleine Raketen in den Orbit.

offset-path

CSS kannte lange Zeit 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 lieferten 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 ActionScript an.
Aber wir haben immer noch nichts, was so handlich wie einst die GIF-Animationen wäre: Alles in einer Datei, alles ohne Libraries und ohne Javascript, rein in ein img-Tag und ab die Post.

Das hätte mit SVG und SMIL funktioniert, aber als SVG sich endlich entfalten konnte, haben Blink (Chrome, Opera) und Microsoft schnell einen Riegel vorgesetzt. 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.

Offset-Path-Animationen

Alle SVG-Attribute, die in einem style-Attribut wirken, können heute per CSS animiert werden. Die Animation von Elementen entlang eines Pfades fehlte im CSS-Animations-Angebot für eine lange Zeit.

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

Der grüne Flieger ist ein PNG-Bild, also ein HTML-Element – kein SVG. CSS offset-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-rotate (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-offset-path-Eigenschaften waren bereits zu einem frühen Zeitpunkt in Chrome als motion-path installiert und wurden etwas später umbenannt:

  • aus motion-path wurde offset-path
  • aus motion-offset wurde offset-distance
  • aus motion-rotation wurde offset-rotate

offset-path in SVG

Zu den schönen Seiten von offset-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 …

CSS motion path nur Chrome, Opera, nicht safari,  firefox

Die Ballons schwebten lange nur für Chrome, EDGE, Opera und Firefox. Safari hat sich lange geziert und ist am Ende jetzt doch dazugestoßen und unterstützt offset-path.

c1 {
 offset-path: path( 'M 1169,756 C 2281,362 271,20 229,616 214,1080 56,1151 1169,757 z');
    offset-rotate: 0deg;
    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 der Blink-Entwickler, 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:

SMIL Animation - still working in all modern browsers
<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 Offset Path erzeugt?

Adobe Photoshop 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-rotate agieren sowohl als pures CSS als auch via Javascript. Wie immer, wenn im CSS-Namen ein Bindestrich steht, wird es ein CamelCase (camel case: Weil Javascript keine Bindestriche toleriert, entfallen Bindestriche und der erste Buchstabe nach dem Bindestrich wird groß geschrieben).

Pfad-Animation mit getPointAtLength und getTotalLength

Jetzt sitzt ja nicht jede Animation in einem SVG-Bild, so dass SMIL zum Einsatz kommen kann. 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.
const p = document.createElementNS('http://www.w3.org/2000/svg','path');
const q = document.createElementNS('http://www.w3.org/2000/svg','path');
const r = 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');
q.setAttribute('d','M 755.5,115.9 C 631.2,455.6 228.6,-301.2 201.4,371.1');
r.setAttribute('d','M 736.9,162 C 830.4,634.8 378.6,-273.2 203.2,357.6');
//var abox = document.getElementById('abox');
const ff = document.getElementById('ff');
const ie = document.getElementById('ie');
const ap = document.getElementById('ap');
const head = document.getElementById('head');
head.setAttribute('transform','translate(140,220) rotate(0)');
const len = p.getTotalLength();
const len2 = q.getTotalLength();
const len3 = r.getTotalLength();
let ic = 0;
let repeater;
let open = 0;

function swallow () {
	const pct = ic / 250;
	const pt = p.getPointAtLength(pct * len);
	const qt = q.getPointAtLength(pct * len);
	const rt = r.getPointAtLength(pct * len);
	ff.setAttribute('transform','translate(' + pt.x + ',' + pt.y + ') rotate(' + ic + ')');
	ie.setAttribute('transform','translate(' + qt.x + ',' + qt.y + ') rotate(' + ic + ')');
	ap.setAttribute('transform','translate(' + rt.x + ',' + rt.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;
		//cancelAnimationFrame(repeater);
	}
	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.

2024-02-12 SITEMAP BLOG