0

Below is a contrived example where I append two elements to a page. The first box has a decorative class given to it immediately. The second box has the class given to it after a setTimeout of 1ms has elapsed.

In my example, I appear to always see the second box transition. However, in my larger application, I infrequently see an element rendered without its transition. The element transitions in OK when I attempt to reproduce the issue, but then, a while later after many successful transitions, I see it once again appear without its transition.

I'm wondering if the setTimeout fix is guaranteed to work. Is my problem a race condition, or is my problem elsewhere?

$('#runExample').click(function() {
  $('.example').remove();
  var example = $('<div>', {
    'class': 'example'
  });

  $('body').append(example);
  example.addClass('is-colorful');

  var example2 = $('<div>', {
    'class': 'example'
  });

  $('body').append(example2);

  setTimeout(function() {
    example2.addClass('is-colorful');
  }, 1);
});
.example {
  width: 200px;
  height: 200px;
  background-color: red;
  transition: background-color 2s;
  display: inline-block;
  margin: 0 10px;
}
.example.is-colorful {
  background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='runExample'>
  Run Example
</button>
Sean Anderson
  • 27,963
  • 30
  • 126
  • 237
  • Your setTimeOut duration is too low. Best you can try is 16~17ms, but most of the devices will need 300 milliseconds. Give it a try. Use opacity transitions to ease the user's eye. – Christian Bonato Dec 04 '14 at 01:43
  • 1
    Do you have any resources to support what you're saying? I was under the impression that the minimum setTimeout value was determined by each browser. There are many examples of using a value of 0ms or 1ms to apply transitions on SO. For instance: http://stackoverflow.com/a/7070241/633438. MDN does not cite a specific timeout duration when discussing the usage of a setTimeout. Would it be better to force the browser to reflow manually instead of using a setTimeout? i.e. example2.position(); instead? – Sean Anderson Dec 04 '14 at 01:48
  • A good article on setTimeOut and not its limitations, rather the limitations of the browsers. Read "What’s wrong with setTimeout and setInterval?" on http://creativejs.com/resources/requestanimationframe/ – Christian Bonato Dec 04 '14 at 01:52
  • 1
    Ahhh. I completely spaced on requestAnimationFrame. I suspect that using that over setTimeout will ensure that the browser has reflowed the appended element every time. It seems to be working at the moment. I will give it a spin. – Sean Anderson Dec 04 '14 at 01:55

1 Answers1

1

I think that a more correct solution is to rely on window.requestAnimationFrame as opposed to window.setTimeout. While setTimeout works in my contrived example it does not come with a guarantee that reflow has occurred. This is exactly what requestAnimationFrame was designed for!

$('#runExample').click(function() {
  $('.example').remove();
  var example = $('<div>', {
    'class': 'example'
  });

  $('body').append(example);
  example.addClass('is-colorful');

  var example2 = $('<div>', {
    'class': 'example'
  });

  $('body').append(example2);

  requestAnimationFrame(function() {
    example2.addClass('is-colorful');
  }, 1);
});
.example {
  width: 200px;
  height: 200px;
  background-color: red;
  transition: background-color 2s;
  display: inline-block;
  margin: 0 10px;
}
.example.is-colorful {
  background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='runExample'>
  Run Example
</button>
Sean Anderson
  • 27,963
  • 30
  • 126
  • 237