0
votes

I'm trying to ditch setTimeout-based JavaScript in favor of a CSS transition for a one-second highlight. Instead of changing the background color instantly or even fading between two background colors, I'd like to first switch to yellow immediately, then fade to the proper color.

The way I imagine it should work is I set the class to something with a yellow background, then change it to a class with a transition property and a new color. This just fades to the final color instead of starting from yellow. I don't think I can attach the transition to the element irrespective of class or the two class changes will overlap and run their animations at the same time.

Clearly I need to be structuring things in a different way to accomplish this. I must not be grasping the basics of when transitions actually occur when attached to classes that are added and removed.

<style>
.highlight  { background-color: yellow; }
.selected   { background-color: black; -moz-transition: background-color 2s linear; }
</style>

<div id="samp" onclick="flash();">SAMPLE</div>

<script>
function flash() {
    document.getElementById("samp").className = "highlight";
    document.getElementById("samp").className = "selected";
}
</script>
2

2 Answers

1
votes

After consulting IRC, it was determined the root cause of this was the browser waiting until a script block was complete before attempting a repaint/redraw. It was as if the highlight class was never applied. For this reason, Lea's solution above in fact does work if the timeout is increased. The exact timeout that works must depend on the repaint interval.

I searched for ways to force a repaint and came across an Opera blog post warning against measuring as it causes a repaint. Simply inserting var x = document.getElementById("samp").offsetWidth; between the two lines setting className causes it to start the transition from yellow as desired.

What I find interesting is that the optimization done by both Webkit and Gecko--waiting to redraw until a script block is complete--is reasonable when the actions taken are mostly stateless, as CSS is. That is, regardless of how many changes are made, a browser could discard all previous styles and be correct in applying the last. However, with transitions, CSS has become stateful, and this optimization actually produces very different results than if it were turned off.

0
votes

You need to switch the class with a timeout:

function flash() {
    document.getElementById("samp").className = "highlight";

    setTimeout(function(){
        document.getElementById("samp").className = "selected";
    }, 10);
}

also, this is offtopic but a good practice is to avoid redundant DOM queries and cache elements in variables:

function flash() {
    var samp = document.getElementById('samp');

    samp.className = "highlight";

    setTimeout(function(){
        samp.className = "selected";
    }, 10);
}