-1

I have an element which functions as a tri-state checkbox. I want to run an animation on that element whenever the state changes. Essentially, the element starts with no classes attached to indicate the first state. Then I add a class for one state, then remove that class and add a different one for the second state.

It works on the first click but the animation doesn't play on subsequent clicks. Here's what I have so far:

$('button').click(function() {
  var $div = $('div');
  if (!$div.hasClass('is-colored')) {
    $div.addClass('green is-colored');
  } else {
    $div.toggleClass('green red');
  }
});
@keyframes Animation {
  from {
    opacity: 0;
    transform: scaleX(0) scaleY(0);
  }
  to {
    opacity: 1;
    transform: scaleX(1) scaleY(1);
  }
}
.green {
  background-color: #0F0;
  -webkit-animation: Animation 0.25s linear forwards;
  -moz-animation: Animation 0.25s linear forwards;
  animation: Animation 0.25s linear forwards;
}

.red {
  background-color: #F00;
  /* I tried applying the animation on the second state but this isn't working */
  -webkit-animation: Animation 0.25s linear forwards;
  -moz-animation: Animation 0.25s linear forwards;
  animation: Animation 0.25s linear forwards;
}
div {
  width: 100px;
  height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>Change Color</button>

I know it's possible to restart an animation with JavaScript and as of 3 years ago it didn't seem to be possible to do this without JavaScript.

In short, is it possible to perform the same animation on the same element multiple times using only CSS and toggling classes (i.e, no timeout required)?

Community
  • 1
  • 1
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91

1 Answers1

1

What's happening is because the state never gets a reset so the animation doesn't kick in again. What you want to do is remove the color class as it resets, "wait" (0 seconds) then have the new class kick in for the animation.

The change is like this for green, see below for full changes:

$div.removeClass('green');

setTimeout(function() {
    $div.addClass('red');
}, 0);

Edit: To do this without javascript delay. The only way is to create another version of the animation so it constantly runs a different animation:

$('button').click(function() {
  var $div = $('div');
  if (!$div.hasClass('is-colored')) {
    $div.addClass('green is-colored');
  } else {
    $div.toggleClass('green red');
  }
});
@keyframes Animation {
  from {
    opacity: 0;
    transform: scaleX(0) scaleY(0);
  }
  to {
    opacity: 1;
    transform: scaleX(1) scaleY(1);
  }
}

@keyframes Animation2 {
  from {
    opacity: 0;
    transform: scaleX(0) scaleY(0);
  }
  to {
    opacity: 1;
    transform: scaleX(1) scaleY(1);
  }
}

.green {
  background-color: #0F0;
  -webkit-animation: Animation 0.25s linear forwards;
  -moz-animation: Animation 0.25s linear forwards;
  animation: Animation 0.25s linear forwards;
}

.red {
  background-color: #F00;
  /* I tried applying the animation on the second state but this isn't working */
  -webkit-animation: Animation2 0.25s linear forwards;
  -moz-animation: Animation2 0.25s linear forwards;
  animation: Animation2 0.25s linear forwards;
}
div {
  width: 100px;
  height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>Change Color</button>
jerrylow
  • 2,569
  • 1
  • 15
  • 25
  • Thanks for the useful answer and I may have to take this route. Unfortunately, I messed up and forgot to mention that I want to avoid using a timeout if at all possible (just now edited the question). If it's not possible, then I'll make the change. – Mike Cluck Jun 24 '16 at 17:39
  • @MikeC I'm not sure why you can't use timeout but I've edit the answer to not use javascript changes. The only change is adding another animation and this is a pure CSS change. – jerrylow Jun 24 '16 at 18:05
  • It's not that I can't, it's just that I have a framework handling the class changes so it's inconvenient for me to perform the timeout myself. This does exactly what I want. Thanks! – Mike Cluck Jun 24 '16 at 18:07