setTimeout fix for -webkit-transition
Here's a simple animation which utilizes webkitTransition:
Click to animate
The code behind this example is not complicated:
element.style.webkitTransitionProperty = 'left';
element.style.webkitTransitionDuration = '2s';
element.addEventListener('click', function () {
this.style.left = '100px';
this.addEventListener('webkitTransitionEnd', function () {
this.style.left = 0;
});
});
The following example, though, does not act as one might expect!
Click to reposition
The code:
element.style.left = '100px';
element.style.webkitTransitionProperty = 'left';
element.style.webkitTransitionDuration = '2s';
Here are the instructions this code attempts to provide:
- Set the element's
leftvalue to '100px' (the page should immediately be redrawn). - Set
webkitTransitionPropertyandwebkitTransitionDuration, to apply a transition to future changes in the value ofleft.
What actually happens — as you'll have seen if you're viewing this page in a recent version of Safari or Chrome — is that the transition is applied to the preceding update. This behaviour strikes me as strange, but I have very little understanding of how these transitions are meant to be effected by the browser.
I did manage to get the element to behave as I had intended:
Click to reposition
The working code:
element.style.left = '100px';
setTimeout(function () {
element.style.webkitTransitionProperty = 'left';
element.style.webkitTransitionDuration = '2s';
}, 0);
For some reason wrapping the webkitTransition* declarations in an anonymous
function passed to setTimeout with no delay prevents the transition from
being applied retroactively. I wondered whether closure would be sufficient,
but no, setTimeout seems to be the remedy for this "quirk".
I'd love to know whether the behaviour described here is correct behaviour. If I manage to find the answer to this I'll post an update. If you are able to enlighten me, please do so by leaving a comment!
Update —
I've just been watching one of the WWDC 2010 session videos, and it turns out the the fix I stumbled upon is actually the "correct" solution.
From Session 504 – CSS Effects, Part 2: Galleries and 3D Effects:
Aside: How Browsers Apply CSS Styles
- Browsers optimize away redundant style changes
- This matters with transitions, because they are temporal
var box = document.getElementById('box');
box.style.backgroundColor = 'red';
box.style.webkitTransition = 'background-color 2s';
window.setTimeout(function() {
box.style.backgroundColor = 'blue';
}, 0);
Possibly related posts
- Duplicating arrays in JavaScript
- Bitwise NOT operator proves useful in JavaScript
- Associative arrays in JavaScript
- MooTools every method
- Extra comma considered harmful