SVG-Animation und CSS-Transforms: Eine komplizierte Liebesgeschichte

Avatar of Jack Doyle
Jack Doyle am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Text ist ein Gastbeitrag von Jack Doyle, Autor der GreenSock Animation Platform (GSAP). Jack beschäftigt sich schon lange intensiv mit Webanimationen und versucht, diese einfacher und besser zu gestalten. Er hat hier schon einmal geschrieben und erklärt, wie JavaScript-Animation die performanteste Wahl sein kann (Google empfiehlt sie sogar). Dieses Mal konzentriert er sich auf SVG-Animationen, einige ziemlich beängstigende Probleme, auf die Sie bei der Manipulation mit CSS stoßen können, und wie Sie diese Probleme lösen können.

SVG ist heutzutage sehr beliebt, und die Browserunterstützung ist im Allgemeinen ausgezeichnet... mit einer auffälligen Ausnahme: CSS-Transforms. Das ist besonders schmerzhaft, wenn es um Animationen geht, da Skalierung, Positionierung, Drehung und Verzerrung so grundlegend sind.

Schnallen Sie sich an, denn es wird eine holprige Fahrt. Aber keine Sorge; diese komplizierte Liebesgeschichte hat ein glückliches Ende. In diesem Artikel führe ich Sie durch einige der Probleme und zeige Ihnen dann eine Technik, die das Verhalten browserübergreifend harmonisiert und in der neuesten Version der GreenSock Animation Platform (GSAP) integriert ist.

Browser-Bugs & Inkonsistenzen

Schauen Sie sich zuerst diese animierten GIFs an, die die exakt gleiche CSS-Animation von zwei <rect>-Elementen in verschiedenen Browsern zeigen (zumindest Stand November 2014).

Siehe den Pen GIFS: SVG + CSS Transform Probleme von GreenSock (@GreenSock) auf CodePen.

  • IE und Opera respektieren CSS-Transforms bei SVG-Elementen überhaupt nicht. Stattdessess müssen Sie den Wert dem transform Attribut zuweisen.
  • Firefox respektiert keine %-basierten Ursprünge.
  • Das Zoomen in Safari zerstört die Synchronisation zwischen %-basierten und px-basierten Ursprüngen.
  • Firefox erkennt keine Schlüsselwort-basierten Ursprünge wie "right bottom", und Safari verändert sie, wenn der Zoom etwas anderes als 100% ist.
  • In allen Browsern werden px-basierte Ursprünge für SVG-Elemente anders gemessen als für andere DOM-Elemente (siehe unten).

Hier ist ein Video, das diese Fehler demonstriert.

Betrachten Sie transform-origin als den Punkt, um den sich alle Drehungen und Skalierungen drehen, als ob ein Stift ihn dort festhalten würde.

Wo ist mein transform-origin?

Normalerweise würden Sie, wenn Sie von der Mitte eines Elements drehen oder skalieren möchten, transform-origin: 50% 50% setzen. Prozente beziehen sich auf die eigene native Größe des Elements, sodass 50% seiner Breite und 50% seiner Höhe genau in der Mitte landen. Alle wichtigen Browser unterstützen %-basierte Ursprünge für reguläre DOM-Elemente, aber nur wenige unterstützen sie für SVG-Elemente.

Wie sieht es mit px-basierten Werten aus? Die Unterstützung ist ausgezeichnet, aber es gibt ein weiteres Problem: Wie unten gezeigt, misst SVG px-basierte Werte relativ zum 0,0-Koordinaten des übergeordneten SVG, während jedes andere DOM-Element (wie ein <div>) es relativ zu seiner eigenen oberen linken Ecke misst. Wenn Sie es also zentrieren möchten, müssen Sie die Mathematik durchführen, um die Koordinaten in SVG zu plotten (Sie können dafür getBBox() JS verwenden). Folglich können Sie nicht dasselbe CSS auf ein reguläres DOM-Element und ein SVG-Element anwenden und erwarten, dass sie sich gleich verhalten.

Siehe den Pen SVG transform-origin Demo von GreenSock (@GreenSock) auf CodePen.

Eine Lösung

Es wäre schön, wenn ich einen reinen CSS-Trick hätte, der hier funktioniert, aber da IE und Opera CSS-Transforms auf SVG-Elementen komplett ignorieren und es in den meisten anderen Browsern Fehler gibt, verlassen wir uns auf eine der unglaublichen Stärken von JavaScript: seine Flexibilität. Selbst wenn jeder Browser nächste Woche seine Fehler behebt, können wir der Tatsache nicht entgehen, dass die SVG-Spezifikation px-basierte Transform-Ursprünge sehr viel anders behandelt als andere DOM-Elemente, sodass CSS-Transforms an diese Spezifikation gebunden sind. Soweit ich das beurteilen kann, ist die einzige praktikable längerfristige Lösung eine JavaScript-basierte. Außerdem bietet JS viele weitere Vorteile, aber das ist ein Thema für einen anderen Artikel.

Das Ziel: Verschiedene Transform-Eigenschaften (Drehung, Skalierung, Positionierung und Verzerrung) von SVG-Elementen auf die gleiche Weise wie "normale" DOM-Elemente animieren zu können, während ein identisches Verhalten über alle wichtigen Browser hinweg geliefert wird. Wir sollten auch in der Lage sein, den Transform-Ursprung mit standardmäßigen CSS-ähnlichen Werten festzulegen, einschließlich Prozentsätzen, px oder Schlüsselwörtern wie "right bottom". Oh, und es muss *SCHNELL* sein.

Falls Sie GreenSock's GSAP noch nicht kennen: Es ist eine hochperformante, professionelle JavaScript-Animationsbibliothek mit unvergleichlichen Sequenzierungs-Tools, Laufzeitkontrollen und Flexibilität (animieren Sie buchstäblich alles, was JavaScript berühren kann). Google empfiehlt es für JS-basierte Animationen, und es ist bis zu 20-mal schneller als jQuery.

Hier ist eine Übersicht über die Technik, die hinter den Kulissen von GSAP verwendet wird (wir gehen nicht ins Detail der Matrixmathematik, da dies den Rahmen dieses Artikels sprengt). Die folgende Demo zeigt, was GSAP tut, wenn Sie versuchen, ein SVG <rect> um seine Mitte zu drehen, indem Sie einen transform-origin von "50% 50%" angeben.

Siehe den Pen SVG transform-origin Lösung von GreenSock (@GreenSock) auf CodePen.

Die resultierende matrix()-Zeichenkette sollte entweder dem CSS-Stil des Elements oder dem transform-Attribut übergeben werden, je nachdem, was für den jeweiligen Browser notwendig ist.

Wenn Ihnen das keinen Sinn ergeben hat, ist das in Ordnung – all das geschieht automatisch hinter den Kulissen für Sie in GSAP.

Das Ergebnis

Wir erhalten nicht nur ein harmonisiertes Verhalten über Browser hinweg und eine konsistente Animations-API für SVG- und Nicht-SVG-Elemente, sondern der Animationscode, den wir schreiben müssen, ist winzig im Vergleich zur (kaputten) reinen CSS-Animation.

TweenMax.to("#svg, #div", 2, {
  rotation:360, 
  transformOrigin:"50% 50%"
});

Hier ist eine Demo, die eine Sequenz mehrerer Ursprünge zeigt. Beachten Sie, dass alles für das SVG <rect> und das <div> gleich funktioniert.

Siehe den Pen SVG CSS Transforms Timeline von GreenSock (@GreenSock) auf CodePen.

Tipps zum Animieren von SVG mit GSAP

Ich werde die GSAP-API hier nicht erklären (siehe den Artikel zum Einstieg dafür), aber ich gebe ein paar SVG-bezogene Tipps. Holen Sie sich GSAP auf github oder laden Sie es von GreenSock.com herunter.

  • Anstatt alle Transform-Komponenten in einer einzigen "transform"-Zeichenkette wie in CSS zu kombinieren, lässt GSAP Sie jede einzeln definieren, und Sie müssen sich keine Gedanken über die Reihenfolge der Operationen machen (sie ist immer konsistent). Beachten Sie auch, dass GSAP x und y verwendet, um sich auf translateX() und translateY() zu beziehen, und rotation für rotate(). Alles andere ist gleich (scaleX, scaleY, skewX und skewY).
    #yourID {
        animation-name: myAnimation;
        animation-duration: 2s;
        animation-timing-function: ease-out;
        transform-origin: right bottom;
    }
    @keyframes myAnimation {
        from {transform: none;}
        to {transform: rotate(270deg) scaleX(0.5) translateX(100px);}
    }
    TweenMax.to("#yourID", 2, {
        rotation:270, 
        scaleX:0.5, 
        x:100, 
        transformOrigin:"right bottom"
    });
  • Sie können das Roh-Element als Ziel (erster Parameter), Selektor-Text oder ein Array von Elementen übergeben.
  • Um numerische Attribute von SVGs (anstelle von CSS-Eigenschaften) zu animieren, verwenden Sie ein attr:{}-Objekt wie
    TweenMax.to("#circle", 2, {attr:{cx:200, cy:300, r:20}, ease:Power2.easeInOut});
  • Sie können auch 3D-Eigenschaften wie z, rotationX, rotationY und perspective verwenden, aber einige Browser wie IE und Opera werden diese bei SVG-Elementen nicht erkennen.
  • Es ist am besten, transformOrigin direkt über GSAP festzulegen und nicht in CSS, da verschiedene Browser sie über getComputedStyle() inkonsistent melden.
  • Sie können fast jeden CSS-Wert animieren, einschließlich Farbeigenschaften wie fill und stroke.
  • Wenn Sie viel Sequenzierung durchführen möchten, empfehle ich dringend, sich die Videos hier und hier anzusehen. Sequenzierung ist eine der bedeutendsten Stärken von GSAP.

Weitere Ressourcen