How can I restart a CSS animation with random values in a loop?

When you replace the element with the cloned element, you should reassign the animationend event listener:

var clone = myElement.cloneNode(true);
clone.addEventListener('animationend', changeAnimation, false);
myElement.parentNode.replaceChild(clone, myElement);

By the way, variables in JavaScript can't contain -, so my-element should be myElement.


Another simple idea is to rely on animationiteration and make the animation to run infinite then you no more need to clone the element. You simply change the animation name each iteration and you will have the needed effect:

var myElement = document.querySelector('#my-element');

function setProperty(number) {
  myElement.style.setProperty('--animation-name', 'vibrate-' + number);
}

function changeAnimation() {
  var number = Math.floor(Math.random() * 3) + 1;
  setProperty(number);
}

myElement.addEventListener('animationiteration', changeAnimation, false);
#my-element {
  width: 50px;
  height: 50px;
  background: #333;
}

#my-element {
  animation: 3.3s alternate infinite var(--animation-name,vibrate-1);
}

@keyframes vibrate-1 {
  0% {
    opacity: 0;
    transform: scale(0.95);
  }
  50% {
    opacity: 1;
    transform: scale(1);
    background:green;
  }
  100% {
    opacity: 0;
    transform: scale(0.9);
  }
}

@keyframes vibrate-2 {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }
  50% {
    opacity: 1;
    transform: scale(0.9);
    background:red;
  }
  100% {
    opacity: 0;
    transform: scale(0.5);
  }
}

@keyframes vibrate-3 {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  50% {
    opacity: 1;
    transform: scale(1);
    background:blue;
  }
  100% {
    opacity: 0;
    transform: scale(0.8);
  }
}
<div id="my-element"></div>

Another way is to simply keep one animation and adjust the scale values (or any other values) and you will have a better random behavior.

var myElement = document.querySelector('#my-element');

function changeAnimation() {
  var n1 = Math.random();
  myElement.style.setProperty('--s1',n1);
  var n2 = Math.random();
  myElement.style.setProperty('--s2',n2);
  var c1 = Math.floor(Math.random()*255);
  myElement.style.setProperty('--c1',c1);
  var c2 = Math.floor(Math.random()*255);
  myElement.style.setProperty('--c2',c2);
}

myElement.addEventListener('animationiteration', changeAnimation, false);
#my-element {
  width: 50px;
  height: 50px;
  background: #333;
}

#my-element {
  animation: 3.3s alternate infinite vibrate;
}

@keyframes vibrate {
  0% {
    opacity: 0;
    transform: scale(var(--s1,0.95));
  }
  50% {
    opacity: 1;
    transform: scale(1);
    background:rgb(255,var(--c1,0),var(--c2,0));
  }
  100% {
    opacity: 0;
    transform: scale(var(--s2,0.9));
  }
}
<div id="my-element"></div>