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
transformAttribut 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
xundyverwendet, um sich auftranslateX()undtranslateY()zu beziehen, undrotationfürrotate(). Alles andere ist gleich (scaleX,scaleY,skewXundskewY).#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 wieTweenMax.to("#circle", 2, {attr:{cx:200, cy:300, r:20}, ease:Power2.easeInOut}); - Sie können auch 3D-Eigenschaften wie
z,rotationX,rotationYundperspectiveverwenden, aber einige Browser wie IE und Opera werden diese bei SVG-Elementen nicht erkennen. - Es ist am besten,
transformOrigindirekt über GSAP festzulegen und nicht in CSS, da verschiedene Browser sie übergetComputedStyle()inkonsistent melden. - Sie können fast jeden CSS-Wert animieren, einschließlich Farbeigenschaften wie
fillundstroke. - 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
- Sara Soueidan hat einen fantastischen Artikel über die Animation von SVG durch SMIL geschrieben.
- Mega-Liste SVG-bezogener Ressourcen hier auf CSS-Tricks.
- Schauen Sie sich Joni Trythall's wunderschönes Pocket Guide to Writing SVG an.
- Mythen aufdecken: CSS-Animationen vs. JavaScript
Für Firefox ist transform-origin für SVG einfach nicht unterstützt. Es wurde implementiert, aber aufgrund von Leistungsproblemen zurückgezogen. Es gab kürzlich einige Arbeiten, um den Patch anzupassen und ihn wieder einzuführen. Wenn jemand das prüfen möchte, siehe Bug 923193.
Ich würde gerne mehr Artikel über die browserübergreifenden SVG-Inkonsistenzen sehen. Ich bin selbst auf eine Reihe davon gestoßen.
Ihre Art zu erklären ist großartig, und für Leser leicht verständlich. Wow, es muss viel Zeit gekostet haben, das so attraktiv und lesefreundlich zu gestalten. Tolle Arbeit, ich freue mich auf mehr solcher Arbeiten. Ich werde versuchen, meine Arbeit so überzeugend zu gestalten wie Ihre :)
Interessante Einblicke, wie Browser SVG-Animationen rendern. Danke Jack :)
Weiß jemand, ob diese Browserprobleme nur für Inline-SVG gelten? Oder gibt es auch Bedenken bei img-Tags, die auf .svg enden?
Ich bin mir nicht sicher, wie Sie Ihre SVG-Bilder animieren möchten, daher hier eine kurze Aufschlüsselung der beiden Optionen.
Wenn Sie den Inhalt eines als <img> verwendeten SVG animieren möchten, müssen Sie SMIL-Animationen im XML-Markup oder CSS-Animationen in einem eingebetteten Stylesheet verwenden, beides innerhalb der Haupt-.svg-Datei. Keine Browser unterstützen externe Ressourcen oder JavaScript innerhalb von Bilddateien.
Wenn Sie jedoch das gesamte <img>-Element auf Ihrer Webseite verschieben möchten, können Sie die gleichen CSS-Transforms wie für jede andere Art von Bild (oder jedes andere Element der Webseite) verwenden. Sowohl CSS-Animation als auch JavaScript-basierte Animation sollten funktionieren. SMIL ist keine Option, da das <img> ein HTML-Element und kein SVG-Element ist. Das für transform-origin verwendete Koordinatensystem basiert auf der oberen linken Ecke des <img>-Elements, gemäß der aktiven box-sizing-Eigenschaft, und der Standardursprung wäre die Mitte des Bildes.
Gute Arbeit!
Ich habe darauf gewartet, das zu sehen!
Zum transformOrigin: Können Sie es wie normales SVG verhalten lassen? Denn im Moment machen Sie es wie HTML, aber manchmal (für mich "jetzt gerade") möchte ich Dinge von einem einzigen Punkt aus drehen können.
Sicher, Otto, Sie könnten getBBox() verwenden, um den Versatz vom Ursprung der übergeordneten SVG-Leinwand zu berechnen. Hier ist eine einfache Funktion, die Sie in Ihren Tweens wiederverwenden könnten.
Sie übergeben also nur das SVG-Element und optional einen Versatz/Punkt, um den sich die Dinge drehen/skalieren/verzerren sollen, und es gibt den entsprechenden transformOrigin zurück, z. B. "-150px -75px". Es wäre offensichtlich für jedes Element anders, deshalb habe ich es in eine Funktion verpackt, damit Sie es wiederverwenden können und es die Arbeit für Sie erledigt. Hilft das?
Habe es noch nicht ausprobiert, aber bitte werfen Sie einen Blick auf dieses Codebeispiel...
http://codepen.io/anon/pen/MYWjJm
Wie Sie sehen werden, ist mein Problem etwas tiefer: Ich muss Elemente mit Dingen darin animieren.
Im Beispiel füge ich ein kleines hinzu, um als Drehpunkt zu dienen, damit ich Ihre Funktion nicht brauche.
Es funktioniert in Firefox und Chrome, aber nicht in IE11.
Otto, das ist wahrscheinlich etwas, das in den GreenSock-Foren (http://greensock.com/forums/) und nicht in den Kommentaren hier behandelt werden sollte, aber das Problem lag darin, dass Ihr zentrales "g"-Element ein Waisenkind war, als Sie x/y gesetzt haben; Browser behandeln SVG-Elemente unterschiedlich, wenn sie keinen SVG-Elternteil haben, wodurch die Logik in CSSPlugin ausgelöst wurde, um sie entsprechend zu bewerten. Ich werde Code in 1.14.3 hinzufügen, um dies zu umgehen, aber vorerst sollte es so einfach sein wie das Umdrehen von zwei Zeilen in Ihrem Code.
Ich bin vor 2 Wochen auf dieses Problem gestoßen, habe es auch mit JS gelöst, aber ich habe SnapSVG verwendet. Es hat die X- und Y-Mittelpunkte in den Eigenschaften des ausgewählten Objekts, sodass Sie einfach den Mittelpunkt ermitteln und animieren können.
Prost.
Gibt es eine Möglichkeit, dass Greensock die Farben von Pfaden und Rechtecken animieren kann? Ich habe versucht, einzelne Eigenschaften mit Greensock zu animieren, aber ich hatte nicht viel Erfolg.
Sicher, es sollte so einfach sein wie
Hier ist ein einfaches Codepen: http://codepen.io/GreenSock/pen/vEEjeQ
Mir ist aufgefallen, dass alle Ihre Überschriften unter dem Hauptartikel einen negativen unteren Abstand zu haben scheinen, was zu einem inkonsistenten Erscheinungsbild führt. Im Gegensatz zur Art und Weise, wie Überschriften auf dem Rest Ihrer Seite behandelt werden, scheint etwas nicht zu stimmen.
Da Sie jemand zu sein scheinen, der sich sehr um das Aussehen und Gefühl Ihrer Website kümmert, frage ich mich, ob dies eine bewusste Designentscheidung ist oder ob es eine Situation ist, die irgendwann verbessert werden muss.
Hey,
Ich bin auf diese coole interaktive SVG-Weihnachtsanimation gestoßen.
Es ist ein Google Chrome Experiment.
Bitte schauen Sie es sich an.
https://ihatetomatoes.net/svg-christmas/