Mit CSS-Animationen (ala @keyframes) ist es nicht so einfach, wie man vielleicht denkt, sie "neu zu starten".
Nehmen wir an, Sie legen fest, dass sie einmal ausgeführt werden soll
.run-animation {
animation: my-fancy-animation 5s 1;
}
Sie lassen das zum Beispiel auf Ihrem Logo laufen
<h1 id="logo" class="run-animation">
Fancy Logo
</h1>
Dann möchten Sie aus irgendeinem Grund, dass diese Animation erneut ausgeführt wird, vielleicht bei einem Klick. Sie denken vielleicht, dass CSS eine Möglichkeit bietet, sie erneut auszulösen, aber soweit ich weiß, tut es das nicht. Sie könnten sogar versuchen, den Klassennamen über JavaScript (jQuery) zu entfernen und wieder hinzuzufügen.
$("#logo").click(function() {
// not gonna work
$(this).removeClass("run-animation").addClass("run-animation");
});
Wenn Sie eine winzige Verzögerung zwischen dem Entfernen und erneuten Hinzufügen der Klasse einfügen (z. B. setTimeout()), funktioniert es, aber ich denke, es versteht sich von selbst, dass das nicht ideal ist. Was Sie wirklich tun müssen, ist, das Element vollständig von der Seite zu entfernen und es neu einzufügen. Als schnelle Demo mit jQuery klonen wir es, fügen es direkt daneben ein und entfernen dann das Original.
$("#logo").click(function() {
var el = $(this),
newone = el.clone(true);
el.before(newone);
$("." + el.attr("class") + ":last").remove();
});
oder die Grundlagen mit reinem JavaScript
const el = this;
var newone = elm.cloneNode(true);
elm.parentNode.replaceChild(newone, elm);
Dieses Problem besteht bei jeder Art von Ereignis. Sagen wir, Sie haben eine Animation, die sofort ausgeführt werden soll, und dann erneut bei :hover. Gleiches Problem, sie wird nicht erneut ausgeführt. Oli Studholme hat einige interessante Forschungsergebnisse dazu. Eine Möglichkeit, dies zu umgehen, besteht darin, zwei Animationen zu haben, die sich bis auf ihren Namen exakt gleichen, dann können Sie umschalten, welche Sie für das :hover-Ereignis (oder was auch immer) verwenden, und es wird funktionieren.
img {animation: spin-cat-1 2s;}
img:active {animation: spin-cat-2 2s;}
@keyframes spin-cat-1 {50%{transform:rotateY(180deg);}}
@keyframes spin-cat-2 {50%{transform:rotateY(180deg);}}
Ein CSS-Präprozessor könnte helfen, dies einfacher zu verwalten, indem er einen Codeblock importiert, sodass Sie ihn nur an einer Stelle pflegen müssen, aber letztendlich ist das aufgebläht. Leider können Sie auch nicht mehrere Keyframe-Animationsnamen in einer Deklaration definieren, was ebenfalls nützlich wäre (und nicht nur dafür, denken Sie an komplexere Animationen, bei denen Sie nur bestimmte Keyframes über eine Basis-Keyframe-Animation neu schreiben könnten).
Oli hat auch mit einer Vielzahl anderer Techniken experimentiert, um es zum Laufen zu bringen, wie z. B. das Ändern von Dauer, Verzögerungen und Iterationen anstelle des Änderns des Namens, aber meiner Meinung nach sind all diese noch schlimmer als das Ändern des Namens.
Update: Eine weitere JavaScript-Methode zum Neustart einer CSS-Animation
Lösen Sie einen Reflow zwischen dem Entfernen und Hinzufügen des Klassennamens aus. Zum Beispiel
// retrieve the element
element = document.getElementById("logo");
// reset the transition by...
element.addEventListener("click", function(e) {
e.preventDefault;
// -> removing the class
element.classList.remove("run-animation");
// -> triggering reflow /* The actual magic */
// without this it wouldn't work. Try uncommenting the line and the transition won't be retriggered.
// Oops! This won't work in strict mode. Thanks Felis Phasma!
// element.offsetWidth = element.offsetWidth;
// Do this instead:
void element.offsetWidth;
// -> and re-adding the class
element.classList.add("run-animation");
}, false);
Anderes JavaScript
Nur zur Vollständigkeit halber: Sie können den Wiedergabezustand einer CSS-Animation auch über JavaScript beeinflussen, z. B. pausieren und neu starten.
element.style.animationPlayState="paused";
element.style.animationPlayState="running";
// Vendor prefixed in old browsers
// element.style.webkitAnimationPlayState="paused";
// element.style.webkitAnimationPlayState="running";
Interessanterweise setzt das natürliche Ende einer CSS-Animation den Wiedergabezustand nicht auf "paused". Das müssten Sie selbst tun. Sagen wir, Sie möchten eine Animation bei jedem Hover neu starten und wären damit einverstanden, jQuery dafür zu verwenden...
$("#thing").hover(function() {
this.style.animationPlayState = "running";
$(this).on('animationEnd', function() {
this.style.animationPlayState = "paused";
});
});
Beachten Sie, wie Sie auf das Ereignis AnimationEnd warten müssen, damit es ausgelöst wird, um es wieder auf "paused" zu setzen, sonst wird es nicht richtig neu gestartet.
Was machen Sie in der letzten Zeile Code? Versuchen Sie nur, das Element zu entfernen? Könnte es nicht über el.remove() gemacht werden?
Sie haben jetzt zwei Elemente mit demselben Klassennamen, sodass die Verwendung von 'el.remove' beide entfernt. Sie müssen also angeben, dass das letzte entfernt werden muss.
Ich glaube, das ist richtig, haha
Kann nicht sein, denn el == $(this). Es wurde nicht manipuliert, soweit ich sehen kann
Schöner Beitrag, Chris!
Paul, ja, es könnte etwas vereinfacht werden, indem man...
http://jsfiddle.net/t3EaG/
Noch vereinfacht
$(this).replaceWith($(this).clone());
$(this).replaceWith($(this).clone(true)); meinte ich
Ich hatte den Gedanken, insertBefore auf das Element anzuwenden, um es erneut einzufügen, aber das funktionierte nicht. Eines jedoch: Die Demo hat die Animation auf dem h1-Element, nicht auf der Klasse, sodass das Entfernen und Ersetzen der Klasse nicht funktionieren kann...
Hmm... eine JS-freie Methode wäre, es mit Übergängen zu machen, anstatt mit Animationen, da diese bei Hover und Active funktionieren, aber das schränkt Sie offensichtlich ein
Es ist sowieso eine Notlösung für diese einfache Animation ;)
Um die Animation neu zu starten, sollte das Hinzufügen der addClass-Methode in ein setTimeout() eingeschlossen werden. Etwas Ähnliches wie dieser Event-Handler
Das ist auch, was ich für das Problem halte. Das Entfernen und Hinzufügen eines Klassennamens im selben Ausführungszyklus (Ihr Event-Handler in diesem Fall) führt dazu, dass sich nichts im DOM ändert, sobald JavaScript nachgibt.
Das setTimeout führt dazu, dass JavaScript zwischen dem Entfernen des Klassennamens und dem erneuten Hinzufügen nachgibt, was es dem Browser ermöglicht, die DOM-Manipulation zu bemerken und darauf zu reagieren.
Sie müssen die addClass-Methode nicht wirklich umschließen, Sie können einfach eine Closure über $(this) innerhalb Ihres onclick-Handlers erstellen und in Ihrem setTimeout-Aufruf darauf verweisen (wie die elem-Variable in Clamsters Kommentar), sodass Sie weiterhin jQuery removeClass und addClass verwenden können, wenn $(this) an elem zugewiesen ist.
Eine weitere Möglichkeit, dies mit addClass/removeClass zu tun, ist das Erzwingen eines Reflows zwischen den Aufrufen, was meiner Meinung nach etwas schöner ist als setTimeout
Hinweis des Herausgebers: Jorge Antunes schrieb, dass dies großartig funktioniert, und stellte eine CodePen-Demo zur Verfügung.
Jesper, ich stimme zu, dass es schöner ist, aber das ist doch der Ansatz, der laut Artikel nicht funktioniert, oder?
Sie können den Klassennamen entfernen, sobald die Animation endet ('webkitAnimationEnd'), und ihn dann wieder hinzufügen, wenn Sie ihn bei einem Klick oder einem anderen Ereignis benötigen. http://jsfiddle.net/nimbu/vxcYJ/
aber wenn es eine unendliche Animation ist?
Ich bin mir nicht sicher, warum Sie eine unendliche Animation neu starten möchten :/
Auf jeden Fall müssen Sie die Eigenschaft webkitAnimation aus dem Stil entfernen und dann nach einer Verzögerung erneut setzen, um sie zu starten.
Das Pausieren von Animationen wird ohnehin von der animation-play-state-Eigenschaft abgedeckt.
Ich wollte nur sagen, wenn Sie ein unendlich wiederholendes Ereignis abbrechen möchten, können Sie nach diesem Ereignis ‘webkitAnimationIteration’ suchen, das ausgelöst wird, wenn die Anzahl der Animationsiterationen größer als 1 ist.
Das ist einfach und elegant – bravo.
Wenn Sie sowieso jQuery verwenden, warum nicht die gesamte Animation in jQuery durchführen, was browserübergreifend kompatibel ist?
Das könnten Sie sicherlich. Es gibt Überlegungen und es hängt von den tatsächlichen Anwendungsfällen ab, daher ist es theoretisch schwer zu debattieren. Beide können Dinge, die der andere nicht kann. JavaScript-basierte Animationen haben eine tiefere Unterstützung, aber CSS-Animationen sind im Allgemeinen flüssiger und können hardwarebeschleunigt werden.
Das stimmt, Chriss, aber Sie machen hier browserabhängige Animationen und egal ob hardwarebeschleunigt oder nicht, Sie brauchen immer noch ein Fallback für Browser, die die Animation nicht mit CSS unterstützen, also könnten Sie sie genauso gut in jQuery machen, es sei denn, Sie haben die Feature-Erkennung und zielen in diesem Fall auf Nicht-Webkit-Browser ab.
Nach allem, was ich gesehen habe, sind jQuery/JavaScript-Animationen flüssiger als CSS3-Animationen...
Und die Debatte geht weiter! Das war eigentlich auch meine Frage. Warum CSS-Animationen und JavaScript-Animationen mischen? Es scheint in Zukunft mühsam zu sein, darauf zurückzukommen.
Ich denke, es ist einfacher, bei einer Sache zu bleiben, und da CSS noch nicht wirklich fertig ist (Browserunterstützung, Unfähigkeit, Animationen neu zu starten), bleiben Sie einfach bei JavaScript.
Die Animation war unter Safari und Chrome flüssig, aber nicht unter IE 8. Unter Firefox habe ich sie noch nicht ausprobiert.
Ich glaube, das liegt daran, dass IE8 CSS-Animationen nicht unterstützt.
Sehr nützlich, danke.
Hallo,
Ich hatte dieses Problem vor nicht allzu langer Zeit, die Art, wie ich es gelöst habe, war, die Klasse zu entfernen und dann einen 0ms-Timer für das erneute Hinzufügen einzustellen.
$('etwas').removeClass('anim').animate({'nichts':null}, 1, function () {$(this).addClass('anim');
});
Einfach und doch effektiv!
Ich werde "Restart CSS Animation" in meine Sprache Türkisch übersetzen.
Der einfachste Weg, CSS-Animationen von vorne zu wiederholen, ist, wenn Elemente in einem Haupt-Wrapper platziert sind.
function Replay(){
var container = document.getElementById(“wrapper”);
var content = container.innerHTML;
container.innerHTML= content;
console.log(“replay”);
}
Ich hatte ein Problem mit Keyframe-Animationen in IE11, und Sie haben dasselbe Problem hier, im Grunde spielen keine der Animationen :(
Ich habe fast keine jQuery-Kenntnisse. Was Sie oben gemacht haben, war SPITZE und perfekt, das einzige, was ich brauche, ist, dass es zeitgesteuert wird, z. B. das Element nach 3 Sekunden entfernen und dann nach 40 Sekunden wieder hinzufügen. Wie gehe ich da vor?