Reliable way to trigger one-way CSS transition?

I have designed a transition that changes instantly background color, then slowly recovers to original color:

body, html {margin: 0px;padding: 0px;}
div {
  padding: 3px;
  margin: 1px 0 1px 0;
  border: 1px solid black;
  background-color: #3377FF;
  transition: background-color .9s ease-in;
}

div:hover {
  background-color: #33FF11;
  transition-duration: 0s;
}
<div> Hello</div>
<div> Hello</div>

This is designed for row in a table to notify user of a change. I’d like to trigger effect this programmatically, but by using the actual CSS.

Row.prototype.blink = function() {
  ... ?
}

I tried to use setTimeout to add and remove class name from the nodes:

$("div").on("click", function() {
  $(this).addClass("updated");
  var _this = this;
  setTimeout(function(){$(_this).removeClass("updated");}, 30);
});
body, html {margin: 0px;padding: 0px;}
div {
  padding: 3px;
  margin: 1px 0 1px 0;
  border: 1px solid black;
  background-color: #3377FF;
  transition: background-color .9s ease-in;
}

div.updated {
  background-color: #33FF11;
  transition-duration: 0s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click div to activate the blink effect:</p>
<div> Hello</div>
<div> Hello</div>

I also tried to use the transitioned event, but the event doesn’t ever trigger:

$("div").on("click", function() {
  $(this).one("transitionend", function(){$(this).removeClass("updated");}); // never happens
  $(this).addClass("updated");
});

I don’t like the setTimeout method, can’t you think of better trick to trigger the blink effect?


solution

The reason the transitionend event isn’t being triggered is because transition-duration is set to 0s. In other words, the transition never begins until the class is removed (but the class isn’t removed because the event isn’t fired).

It really sounds like an animation would be better suited for this. Just listen to the animationend event and remove the class in the callback when the animation ends:

$('div').on('click', function() {
  $(this).addClass('updated').one('animationend', function() {
    $(this).removeClass('updated');
  });
});
body, html {margin: 0px;padding: 0px;}
div {
  padding: 3px;
  margin: 1px 0 1px 0;
  border: 1px solid black;
  background-color: #3377FF;
  cursor: pointer;
}
div.updated {
  animation: updatedFade .9s ease-in forwards;
}
@keyframes updatedFade {
  0% { background-color: #33FF11; }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Hello</div>
<div>Hello</div>

As a work-around to your initial solution, you could change the transition-duration to something extremely short, like 1ms, so that the initial transition is actually started, thereby allowing the transitionend event to be fired:

$("div").on("click", function() {
  $(this).addClass("updated").one("transitionend", function() {
    $(this).removeClass("updated");
  });
});
body, html {margin: 0px;padding: 0px;}
div {
  padding: 3px;
  margin: 1px 0 1px 0;
  border: 1px solid black;
  background-color: #3377FF;
  transition: background-color .9s ease-in;
  cursor: pointer;
}
div.updated {
  background-color: #33FF11;
  transition-duration: 1ms;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Hello</div>
<div>Hello</div>