Grief Grief - 23 days ago 7
CSS Question

CSS transition with pure JS without delay

What I want to achieve is to change some property (

background-color
in the code above) twice from js so that transition would run between them but not from the previous state to the first one. The code above almost never works because timeout is set to zero, it works almost always when it is set at least to 10 and it works always on my machine when I set it to 100. What I also want is to avoid timeouts completely and ether run the code linearly or based on the appropriate event callback (I didn't find any useful so far).

Here is an example (also on jsFiddle):



var outter = document.getElementById('outter');
var test = document.getElementById('test');

test.onclick = function() {
outter.removeChild(test);
test.style.backgroundColor = 'green'
outter.appendChild(test);
setTimeout(function() {
test.style.backgroundColor = 'red'
}, 0);
}

#test {
position: fixed;
left: 2em;
right: 2em;
top: 2em;
bottom: 2em;
background-color:red;

transition-duration: 2s
}

<div id=outter>
<div id=test></div>
</div>




Answer

I managed to do it using a very short transition when going green and using transitionend handlers (which, sadly, still require vendor prefixes — yeesh).

The following works for me with Firefox, Chrome, and IE11. (I should note that you don't have to use classes, I just prefer to keep styling in the CSS; you could use outter.style.transitionDuration = "2s"; and such.)

var outter = document.getElementById('outter');
var test = document.getElementById('test');

function onTransition(element, handler, add) {
  var method = (add ? "add" : "remove") + "EventListener";
  element[method]("transitionend", handler, false);
  element[method]("mozTransitionEnd", handler, false);
  element[method]("webkitTransitionEnd", handler, false);
}

test.onclick = function() {
  // If we're running...
  if (outter.classList.contains("green")) {
    // ...reset
    onTransition(outter, greenToRed, false);
    onTransition(outter, redDone, false);
    outter.classList.remove("green", "red");
  }
  onTransition(outter, greenToRed, true);
  outter.classList.add("green");
};

function greenToRed() {
  onTransition(outter, greenToRed, false);
  onTransition(outter, redDone, true);
  outter.classList.add("red");
}
function redDone() {
  onTransition(outter, redDone, false);
  outter.classList.remove("green", "red");
}
#test {
  position: fixed;
  left: 2em;
  right: 2em;
  top: 2em;
  bottom: 2em;
  background-color: red;
}

.green #test {
  background-color: green;
  transition-duration: 0.0001s;
}
.red #test {
  transition-duration: 2s;
  background-color: red;
}
<div id=outter>
  <div id=test></div>
</div>

The above is just proof-of-concept, of course; it can be refined and cleaned up a fair bit.

Comments