Javascript für CSS-Animationen

CSS Animation restart – CSS Animation mit Javascript neu starten mit animation play state

Ohne besonderes auslösendes Event (z.B. hover oder focus) starten CSS Keyframes-Animationen automatisch, wenn das Dokument im Browserfenster geladen wird.

CSS bietet nur wenige Events, die eine Animation auslösen und kann Animationen nur begrenzt neu starten. Erst Javascript fügt komplexe Animationen zusammen und kann CSS Keyframes Animationen neu starten starten oder die Animation auslösen, wenn die Animation in den Viewport kommt.

Keyframes-Animation erneut starten

CSS-Animationen haben ihre Grenzen, die aber schon mit einer kleinen Dosis Javascript aufgehoben werden. Eine der Grenzen von CSS Keyframes-Animationen:

Wenn eine CSS-Animation beim Laden der Seite ausgeführt und abgelaufen ist, kann sie nicht ohne Weiteres erneut gestartet werden.

.animated-sky {
   height: 1360px;
   background-image: 
      linear-gradient(to bottom, hsl(200,60%,25%) 0%, 
                           hsl(200,60%,55%) 20%, 
                           hsl(200,60%,90%) 30%,
                           hsl(200,60%,90%) 50%,
                           hsl(200,60%,25%) 80%,
                           hsl(200,60%,55%) 100%); 
   animation: daytime 15s;
}

@keyframes daytime {
   from { top: 0}
   to   { top: -1000px}
}

/* So funktioniert der Neustart der Animation nicht */
.container:hover .animated-sky {
   animation: daytime 15s;
}

Um die Animation jetzt bei einem :hover neu zu starten, braucht sie eine weitere, identische @keyframes-Regel mit einem anderen Namen.

@keyframes night {
	from { top: 0}
	to   { top: -1000px}
}

.touch .animated-sky,
.container:hover .animated-sky {
	animation: night 15s;
}

Von Hover zu Touchstart

Das Hovern der Maus hat keine Entsprechung auf Touchscreens: Es gibt kein :touch. Es ist nicht einmal möglich, die Reaktion vorauszusagen: Vielleicht reagiert der Touchscreen auf CSS :hover, vielleicht nicht. Vielleicht friert der Effekt auf dem Touchscreen ein. :hover ist für Benutzer mit der Maus immer noch ein intuitiver Auslöser, aber :hover allein reicht nicht.

<script>
let container = document.querySelector(".container");
container.ontouchstart = function () {
   this.classList.add("touch");
}
</script>

Dafür war also die kleine Zeile .touch .animated-sky, im CSS der Animation …

Restart: CSS-Animation mit Javascript erneut starten

»In order to restart an animation, it must be removed then reapplied.« – CSS Animations Level 1

Die einfachste Technik zum erneuten Start einer CSS Keyframes-Animation ist wohl das Löschen und erneute Einfügen der animierten Elemente. Javascript cloneNode kopiert ein Element mit allen Child Nodes:

CSS bewegt
CSS rotiert
CSS blendet ein
CSS blendet aus
restart

Eine ganz einfache CSS-Animation:

HTML Markup der Animation
<div class="textani">
   <div class="ani t0">CSS bewegt</div>
   <div class="ani t1">CSS rotiert</div>
   <div class="ani t2">CSS blendet ein</div>
   <div class="ani t3">CSS blendet aus</div>
   <div id="trestart">restart</div>
</div>
Das CSS der Keyframes-Animation:
.textani { 
   width: 300px; height: 200px; 
   overflow: hidden; position: relative; 
}

.ani { position: absolute; }
	
.t0 { top: 30px; animation: tmovedown 2s }
.t1 { top: 60px; animation: tmoveup 2s }
.t2 { top: 90px; animation: tmoveleft 2s }
.t3 { top: 120px; animation: tmoveright 2s }

@keyframes tmovedown {
    from { transform: translateY(-200px)}
    to { transform: translateY(0px)}
}
	
#trestart { 
    position: absolute; 
    bottom:0; right: 0; 
}
Javascript: CSS Keyframes-Animation restart
<script>
document.getElementById('trestart').onclick = function () {
    let clone = document.querySelector('.textani').cloneNode();
    let ani = document.querySelectorAll('.ani');
    let len = ani.length;
    for (let i=0; i<len; i++) {
        let clone = ani[i].cloneNode(true);
        ani[i].parentNode.replaceChild(clone, ani[i]);
    }
}
</script>

Javascript startet die komplette Animation bei einem Click auf den Button durch Klonen aller Elemente der Animation und Ersetzen des Originals durch den Klone – also Löschen und Clone einsetzen.

Das wars im einfachsten Fall.

CSS Animation mit animation-play-state starten und stoppen

animation-play-state : paused versetzt eine Animation in eine Wartezustand, bis ein Event mit animation-play-state: running die Sequenz der Keyframes auslöst.

Eine Animation mit animation-play-state: paused wird zwar schon beim Laden der Seite gestartet, sie pausiert aber sofort.

#banner { 
    position: relative; 
}

.ball { 
    position: absolute;
    animation: rolerball 4s alternate infinite paused; 
}
 
@keyframes rolerball {
    from {transform: translateX(0) rotate(0deg)}
    to {transform: translateX(200%) rotate(720deg)}
}

Wird die Animation durch :hover gestartet, läuft sie solange die Maus über dem Element hovert. Sobald die Maus das animerte Element verlässt, springt das Element ruckzuck abrupt zurück auf seine Position vor der Animation.

In vielen Situationen wirkt es natürlicher, wenn die Animation an der Stelle stehenbleibt, an der die Maus das Element verlässt.

let banner = document.querySelector('#banner');

banner.onmouseover = 
banner.ontouchstart = function (evt) {
    this.children[0].style.animationPlayState = 'running';
}
banner.onmouseout = 
banner.ontouchend = function (evt) {
    this.children[0].style.animationPlayState = 'paused';
}

Das spielt die Animation ab, solange die Maus über dem Banner hovert. Verlässt sie das Banner, pausiert die Animation und wird beim nächsten Hovern an dieser Stelle wieder aufgenommen.

Starten mit mouseover und touch

Der CSS-Pseudo-Selektor :hover löst eine CSS-transition oder Keyframe-Animation aus. Auf Touch-Screens gibt es kein zuverlässiges hover. Das touch-Event gibt es wiederum nicht für's CSS.

Das lösen ein paar Zeilen Javascript:

let box = document.querySelectorAll('.box');
for (let i=0; i<box.length; i++) {
	box[i].onmouseover = 
	box[i].ontouch = function () {
		this.classList.add('toggle');
		this.firstElementChild.setAttribute('style','opacity:1');
	}
	box[i].onmouseout = 
	box[i].ontouchend = function () {
		this.classList.remove('toggle');
		this.firstElementChild.setAttribute('style','opacity:0.3');
	}
}

Javascript classList schaltet eine Klasse hinzu oder entfernt sie. classList wird allerdings erst ab IE 10 unterstützt. Wenn IE 9 noch mitgezogen werden muss, gibt es ein classList-Polyfil auf Github.

CSS Animation im Viewport?

Eine Animation starten, wenn sie in den Viewport kommt:

Restart

Drei Elemente werden animiert: Korpus, Head und die Strahlen des Roboters sind CSS Keyframes-Animationen und bestehen jeweils aus einer Gruppe von Elementen.

Position des Elements im Dokument finden
function findPos (obj) {
   let curleft = curtop = 0;
   if (obj.offsetParent) {
      do {
         curleft += obj.offsetLeft;
         curtop += obj.offsetTop;
      } while ( obj = obj.offsetParent);
      return [curleft,curtop];
   }
}

Gefunden bei quirksmode

Bis wohin scrollen?
let topPos = findPos (robox)[1] - robox.offsetHeight - window.innerHeight;

offsetHeight und innerHeight

elem.offsetHeight ist die Höhe eines Elements mitsamt padding, aber ohne margin.

window.innerHeight ist die verfügbare Höhe des Browserfensters in px.

Weit genug gescrollt? Animation starten
window.onscroll = function () {
   if (window.pageYOffset  > topPos ) {
       let clone = robox.cloneNode(true);
       robox.parentNode.replaceChild (clone,robox);
       window.onscroll = null;
       document.querySelector('#newRobot').onclick = function () {
         document.querySelector('.robox').parentNode.replaceChild(document.querySelector('.robox').cloneNode(true),document.querySelector('.robox'))
      }
   }
}

pageYOffset

window.pageYOffset ist die Zahl der Pixel, um die das aktuelle Dokument von der oberen linken Ecke des Browserfensters vertical gescrollt wurde.

IE / Edge: SVG-Animation mit CSS Keyframes

Animationen von SVG-Element mit CSS Keyframes (und Transitions ebenso) funktionieren in IE nur bei CSS-Eigenschaften wie opacity und fill, nicht aber mit transform und rotate.

Dieser Einschränkung unterliegen auch SVG-Animationen mit jQuery, besser mit velocity.js.

CSS Animation restart – CSS Animation mit Javascript neu starten