200924Nov

jQuery-Tutorial: Animationen und Effekte erzeugen

Die jQuery-Bibliothek bietet sehr gute Funktionen für das Animieren von CSS-Eigenschaften. Durch dezente Effekte und Bewegungen kann das Erscheinungsbild von Websites aufgewertet werden. Die Erstellung von Animationen gestaltet sich in jQuery sehr einfach — dennoch muss stets darauf geachtet werden, dass nicht zu viele Bewegungen auf einer Seite stattfinden und die animierten Elemente zudem flüssig bewegt werden. Hier gibt es schon Unterschiede, die vom jeweiligen Browser abhängen. In manchen Fällen sollten also alternative Animationseinstellungen verwendet werden, wenn die Website beispielsweise in Internet Explorer angesehen wird.

Bevor ich mit dem ersten Beispiel beginne, will ich kurz auf den eigentlichen Ablauf einer Bewegung eingehen: Eine Animation zeichnet sich durch die Annäherung an einen Wert (CSS-Eigenschaft) aus, der innerhalb einer festgelegten Zeitspanne vollständig erreicht wird. Die Anzahl der Zwischenbilder, die von jQuery generiert werden, ist für die Geschwindigkeit verantwortlich. Für das menschliche Auge reichen ca. 16 – 18 Einzelbilder pro Sekunde aus, um eine Bewegung flüssig erscheinen zu lassen. Das in Deutschland verwendete PAL-System arbeitet mit 50 Halbbildern, was 25 vollen Bildern pro Sekunde (alle 40 ms ein Bild) entspricht. Dadurch erscheint ein Bewegungsablauf auf dem Bildschirm fließend.
In jQuery ist der Intervall für die Bildwiederholrate auf 13 ms im Code verankert — durch zusätzliche Mathematik, die für eine genaue Berechnung der Zwischenschritte sorgt, werden von jQuery 60 – 65 Bilder pro Sekunde generiert.

jQuery - Bilder pro Sekunde

Durch diesen Unterschied erscheinen Animationen, die mit jQuery erstellt werden, etwas schneller als die üblichen Bewegungsabläufe (Fernsehen, Computer, Kino), an die das Auge gewöhnt ist. Dennoch können HTML-Elemente natürlich immer nur um einen Pixel (außer Opazität) verschoben werden. Als Entwickler sollte man diese Thematik im Hinterkopf behalten — die Berechnungen werden von jQuery übernommen.

In jQuery sind zwei Werte für einen Bewegungsablauf notwendig: Die Dauer (Zeit in Millisekunden) der Animation sowie die CSS-Eigenschaft, die animiert werden soll. Neben diesen beiden Angaben kann zudem noch eine weitere Eigenschaft definiert werden — der Übergang (Tween). Ein Übergang beschreibt eine Kurve, die das Verhältnis zwischen einem Wert und einem Zeitpunkt definiert. Durch Veränderungen der Kurve kann beispielsweise eine Beschleunigung oder ein Abbremsen erreicht werden. Man spricht in diesem Fall von Easing (oder Transition). Der Easing-Parameter in jQuery ist optional. Wird dieser nicht definiert, verwendet jQuery die "Spring"-Transition für den Bewegungsablauf. Bei dieser Transition wird eine Bewegung sowohl am Anfang als auch am Ende der Zeitspanne (Dauer) anhand der Kosinus-Funktion abgebremst.
Neben der "Spring"-Transition gibt steht mit der Core-Bilbliothek von jQuery noch die "Linear"-Transition zur Verfügung, die eine Gerade mit gleichmäßiger Beschleunigung beschreibt. Die Abbildung soll die Kurven veranschaulichen.

jQuery - Easing

Weitere Übergänge (Elastizität, Federung, Exponential, usw.) bietet das jQuery Easing Plugin, auf das ich später eingehen werde.
Für alle folgenden Beispiele habe ich folgenden HTML-Code verwendet, der wie gehabt im body-Bereich in Verbindung mit JS Bin platziert werden kann:

  • Quelltext<div id="box"></div>
  • <div id="box2"></div>

Anschließend habe ich die beiden div-Container mit jQuery angepasst (dieser Code kann wieder vor allen folgenden jQuery-Anweisungen stehen):

  • Quelltext
  • $("div").css({
  • "width": 150,
  • "height": 150,
  • "marginBottom": 20,
  • "background": "blue"
  • })

Ganze Zahlen können in jQuery ohne Anführungszeichen angegeben werden. Alternativ lassen sich solche Angaben auch im Stil von "150px" definieren.
Um ein DOM-Element mit einer Animation zu versehen, stehen in jQuery zum einen vordefinierte Effekte zur Verfügung:

  • show
  • hide
  • toggle
  • slideDown / slideUp / slideToggle
  • fadeIn / fadeOut / fadeTo

Möchte man ein Element also beispielsweise ausblenden lassen, wird folgender Code benötigt:

Ohne die Angabe eines Parameters wird von jQuery ein Standardwert (Default) von 400 ms verwendet — die CSS-Eigenschaft "opacity" des Objekts wird also innerhalb von 400 Millisekunden auf "0" animiert. Bei allen jQuery-Effekten ist zu beachten, dass ein Element nach Ablauf einer Animation die CSS-Zuweisung "display:none" erhält, wenn die Opazität oder eine Größenangabe (width oder height) auf "0" animiert wurde.
Neben dem Standardwert von 400 ms gibt es zudem die Vorgaben "slow" (600 ms) und "fast" (200 ms). Die beiden folgenden Animationen wären also identisch:

  • Quelltext
  • $("#box").fadeOut("slow");
  • $("#box2").fadeOut(600);

Neben diesen vordefinierten Effekten stellt die Funktion "animate()" die Methode dar, mit der sich individuelle CSS-Eigenschaften animieren lassen. Hierbei können auch mehrere Eigenschaften auf einmal oder nacheinander animiert werden. Die Funktion wird verwendet wie folgt:

  • $("element").animate({
  • "eigenschaft": "wert"
  • },
  • duration,
  • easing,
  • callback
  • );

Die 3 Parameter "duration", "easing" und "callback" sind optional — werden diese nicht definiert, gelten wieder die Standardeinstellungen. So wären folgende Deklarationen möglich und zudem identisch:

  • Quelltext
  • $("#box").animate({
  • "marginLeft": 300,
  • "height": 10
  • });
  •  
  • $("#box2").animate({
  • "marginLeft": 300,
  • "height": 10
  • },
  • 400,
  • "swing"
  • );

Mit dem obigen Beispiel werden die beiden div-Container also um 300 Pixel nach rechts bewegt und in der Höhe auf 10 Pixel reduziert — die beiden CSS-Eigenschaften werden gleichzeitig innerhalb von 400 Millisekunden animiert. In jQuery gibt es auch für Animationen zudem die Möglichkeit der Aneinanderreihung (Chaining), so dass Bewegungsabläufe nacheinander erfolgen. Wenn wir dies auf das eben genannte Beispiel anwenden, sieht der Code so aus:

  • Quelltext
  • $("#box")
  • .animate({
  • "marginLeft": 300
  • }, 400)
  • .animate({
  • "height": 10
  • }, 400);

Möchte man nun mehrere Animationen durch Chaining benutzen und diese simultan ablaufen lassen, kann der "queue"-Parameter (Reihe) eingesetzt werden. Das bringt den Vorteil, dass mehrere Animationen mit verschiedenen Zeitangaben durchgeführt werden können. Auf das obige Beispiel bezogen würden mit dem folgenden Code also beide "animate()"-Funktionen gleichzeitig ablaufen, jedoch mit unterschiedlicher Dauer.

  • Quelltext
  • $("#box")
  • .animate({
  • "marginLeft": 300
  • }, {
  • queue: false,
  • duration: 400
  • })
  • .animate({
  • "height": 10
  • }, 800);

Zu beachten ist hierbei, dass bei der Benutzung von "queue" die Dauer mit dem "duration"-Parameter angegeben werden muss.

In jQuery können CSS-Eigenschaften zudem um Zahlenwerte erhöht bzw. verringert werden. Hierfür stehen die Operatoren "+=" und "-=" zur Verfügung, die einfach vor die entsprechende Zahl geschrieben werden müssen:

  • Quelltext
  • $("#box").animate({
  • "marginLeft": "+=200"
  • });
  •  
  • $("#box2").animate({
  • "opacity": "-=0.5"
  • });

Dadurch können Eigenschaften um relative Werte verändert werden, so dass ein DOM-Element beispielsweise von seiner aktuellen Position aus um einen bestimmten Abstand verschoben werden kann.

Weiterhin bietet jQuery eine Callback-Funktionalität (Rückfrage): Hierbei wird eine Funktion aufgerufen, sobald eine Animation vollständig abgelaufen ist. Dies kann in vielen Fällen nützlich sein, vor allem wenn Benutzerinteraktionen (Events) im Spiel sind. Hier ein kleines Beispiel:

  • Quelltext
  • $("#box").animate({
  • "marginLeft": 300
  • },
  • 400,
  • function (){
  • $(this).fadeOut(1000);
  • }
    );

Damit würde das Element mit der ID "box" ausgeblendet werden (fadeOut), sobald es um 300 Pixel nach rechts verschoben wurde. Wie man hier sehen kann, funktioniert die Callback-Funktionalität auch, wenn kein Easing-Parameter definiert ist (obwohl die Anzahl der Argumente variiert). Innerhalb der Callback-Funktion muss zudem "$(this)" verwendet werden, um auf das animierte Element zugreifen zu können.

Ein Callback könnte auch dazu genutzt werden, um eine pulsierende Bewegung (Endlosschleife) zu erzeugen. Hier ein Beispiel:

  • Quelltext
  • jQuery.fn.pulsieren = function(){
  • $(this).each(function(){
  • if (this.zustand) {
  • this.zustand = 0;
  • $(this).animate({
  • "marginLeft": 0,
  • "opacity": 1
  • },
  • function(){
  • $(this).pulsieren();
  • });
  • } else {
  • this.zustand = 1;
  • $(this).animate({
  • "marginLeft": 300,
  • "opacity": 0.5
  • },
  • function(){
  • $(this).pulsieren();
  • });
  • }
  • });
  • }
  •  
  • $("#box, #box2").pulsieren();

Wie man sieht, ist es sehr einfach, eigene Funktionen in jQuery zu integrieren. So lassen sich individuelle Animationen erstellen, die an mehreren Stellen verwendet werden können.

Zum Easing: Um mehr Übergänge als die beiden Standard-Transitions nutzen zu können, muss wie gesagt das jQuery Easing Plugin eingebettet werden. Sobald dies erfolgt ist, kann an der entsprechenden Stelle einfach eine der vom Plugin-Autor definierten Deklaration genutzt werden. Das könnte etwa so aussehen:

  • Quelltext
  • $("#box").animate({
  • "marginLeft": 300
  • },
  • 1000,
  • "easeOutBounce"
  • );
  •  
  • $("#box2").animate({
  • "marginLeft": 300
  • },
  • 1000,
  • "easeOutElastic"
  • );

Um die weiteren Übergänge ausprobieren zu können, hat der Autor auf seiner Website eine Echtzeit-Vorschau der verschiedenen Effekte zur Verfügung gestellt.
Animationen lassen sich zudem unterbrechen — dies könnte beispielsweise in einer animierten Navigation Verwendung finden. Dazu kann die "stop()"-Funktion genutzt werden. In Verbindung damit folgt ein Beispiel, welches zudem mit Events verknüpft ist.

  • Quelltext
  • $("#box")
  • .mouseenter(function(){
  • $(this)
  • .css("cursor", "pointer")
  • .fadeTo(100, 0.5);
  • })
  • .mouseleave(function(){
  • $(this).fadeTo(1200, 1);
  • })
  •  
  • $("#box2")
  • .mouseenter(function(){
  • $(this)
  • .css("cursor", "pointer")
  • .stop()
  • .fadeTo(100, 0.5);
  • })
  • .mouseleave(function(){
  • $(this).stop().fadeTo(1200, 1);
  • })

Beim ersten Container (#box) wird "stop()" nicht verwendet und somit läuft die Animation "fadeTo(1200, 1)" komplett aus. Das zweite div-Element nutzt die "stop()"-Funktion und dadurch wird die Animation unterbrochen. Fährt man mit dem Mauszeiger über die beiden Elemente, wird der Unterschied sichtbar.

Ich habe noch ein kleines Beispiel geschrieben, welches die beiden div-Elemente mit verschiedenen Maus-Events verknüpft. Das Beispiel soll demonstrieren, wie sich Callback-Funktionen ineinander verschachteln lassen:

  • Quelltext
  • $("#box, #box2")
  • .mouseenter(function(){
  • $(this)
  • .css("cursor", "pointer")
  • .fadeTo(100, 0.5);
  • })
  • .mouseleave(function(){
  • $(this).fadeTo(300, 1);
  • })
  • .click(function(){
  • $(this).bewegung();
  • });
  •  
  • jQuery.fn.bewegung = function(){
  • $(this)
  • .animate({
  • "marginLeft": 500,
  • "height": 30
  • },
  • 1000,
  • function(){
  • $(this)
  • .unbind("click")
  • .click(function(){
  • $(this).animate({
  • "marginLeft": 0,
  • "height": 150
  • },
  • 400,
  • function(){
  • $(this)
  • .unbind("click")
  • .bind("click", function(){
  • $(this).bewegung();
  • });
  • });
  • });
  • });
  • }

Die Funktion "bewegung()" sorgt dafür, dass die Elemente nach einem Durchlauf wieder die Event-Funktion erhalten, mit der sie in Bewegung gesetzt werden.

Zum Abschluss sei noch eine weitere Methode der "animate()"-Funktion erwähnt, die es ermöglicht, den Wert für die berechneten Zwischenschritte (Steps) sowie einen Anfangswert zu definieren. Dabei wird eine abgewandelte Syntax der Funktion benutzt. Ich habe dazu wieder eine Funktion (Plugin) geschrieben, mit der für CSS-Eigenschaften Anfangs- und Zielwerte festgelegt werden können.

  • Quelltext
  • jQuery.fn.bereich = function(optionen){
  • var e = $(this);
  • $({
  • zielwert: optionen.von
  • }).animate({
  • zielwert: optionen.bis
  • }, {
  • duration: optionen.dauer,
  • step: function(){
  • e.css(optionen.wert, this.zielwert);
  • }
  • });
  • }
  •  
  • $("#box").bereich({
  • von: 0.5,
  • bis: 1,
  • wert: "opacity",
  • dauer: 1000
  • });
  •  
  • $("#box2").bereich({
  • von: 500,
  • bis: 100,
  • wert: "marginLeft",
  • dauer: 1000
  • });

In Zeile 10 wird die eigentliche Veränderung durchgeführt — in diesem Fall die jQuery-Funktion "css()". An dieser Stelle lässt sich jede Eigenschaft eines DOM-Elements angeben, beispielsweise also auch Text (Zeichenanzahl).

Wie oben erwähnt, ist die Animationsgeschwindigkeit vom Browser des Benutzers abhängig — die JavaScript-Engines der verschiedenen Browser unterscheiden sich, wobei es lediglich in Internet Explorer zu sichtbaren Einbußen kommen kann (hauptsächlich in Verbindung mit Hintergrundbildern).
Daher folgt an dieser Stelle noch eine kleiner Tipp, wie sich in jQuery browserspezifische Einstellungen definieren lassen (Browserweiche). Dadurch können alternative Geschwindigkeiten für den Microsoft-Browser festgelegt werden. Dies ist natürlich nur dann erforderlich, wenn nach mehrfachem Testen in diversen Browsern Unterschiede festgestellt wurden.

  • Quelltext
  • // Unterschiedliche Geschwindigkeiten für Animationen
  • var dauer;
  •  
  • if ($.browser.msie) {
  • dauer = 150;
  • } else {
  • dauer = 300;
  • }
  •  
  • $("#box").animate({
  • "marginLeft": 300
  • },
  • dauer
  • );
  •  
  •  
  • // Komplette Deaktivierung der Animationen in Internet Explorer
  • if ($.browser.msie) {
  • $("#box").css("marginLeft", 300);
  • } else {
  • $("#box").animate({
  • "marginLeft": 300
  • },
  • 300
  • );
  • }

Dieses Beispiel macht natürlich nur bei der Verwendung von Events Sinn, wenn diese an Animationen gekoppelt sind. Es geht hier lediglich um die Browserweiche.

Schließlich gibt es noch zwei nützliche Plugins, mit denen sich die Hintergrundposition (background-position) und Farbwerte (color, background-color) von DOM-Elementen animieren lassen.

Sind die beiden Skripte im head-Bereich eingebettet, können sie mit der "animate()"-Funktion genutzt werden. Ein Beispiel:

  • Quelltext
  • $("#box").animate({
  • "backgroundPosition": "10px 20px"
  • }, 400);
  •  
  • $("#box2").animate({
  • "backgroundColor": "red"
  • }, 400);

Animationen können also einfach oder komplex sein. In jedem Fall sollte man stets darauf achten, dass der Benutzer nicht mit zu vielen Effekten überschüttet wird und eine gewisse Balance bewahrt wird.