1

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>

8
  • 1
    So on click, you want the background to immediately turn green, then spend two seconds transitioning from green to red? Commented Nov 11, 2016 at 11:59
  • @T.J.Crowder Exactly! Most important here is the word 'immediately' Commented Nov 11, 2016 at 12:01
  • I don't understand, wanting to transition from A to B straight away, then A to B from but with a delay. You're already at B. Commented Nov 11, 2016 at 12:05
  • Why would you remove test from DOM then change it's color before it's appended back into DOM? Commented Nov 11, 2016 at 12:08
  • @Crowes from anything to A without a delay and then from A to B with animation Commented Nov 11, 2016 at 13:46

2 Answers 2

5

Without timeouts:

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

test.onmousedown= function() {
    test.style.transitionDuration = "0s";
    test.style.backgroundColor = 'green';
};

test.onmouseup= function() {
    test.style.transitionDuration = "2s";
    test.style.backgroundColor = 'red';
};
#test {
  position: fixed;
  left: 2em;
  right: 2em;
  top: 2em;
  bottom: 2em;
  background-color:red;
}
<div id=outter>
  <div id=test></div>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

I really like your solution because it's the most cunning one and it would work great in the exact the same conditions as I described, however I need to trigger that animation not only with clicks and I cannot rely on user input (mousedown/mouseup pair) here, unfortunately.
1

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.

5 Comments

That seems good except it doesn't work as the original example - clicking at the moment of animation breaks it compeltely and I cannot see any way so far to avoid that in your code.
@Grief: Do you mean clicking it and then clicking it again within the two seconds of green-to-red? And if so, what do you want to happen? Ignore the second click? Start over?
I would like to start the animation over like in the original snippet. Ignoring is as simple as removing onclick handler until transitionend.
@Grief: I've updated to handle that, see the changes to onload.
It works now, thanks a lot. Now I have to understand the approach and apply it to my project :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.