Why is setTimeout necessary when applying the class for my transition to take effect?

I have an element with a transition applied to it. I want to control the transition by adding a class to the element that makes the transition fire. However, if I apply the class too quickly, the transition effect fails.

I assume this is because it .shown

is being placed in a div during the same event loop when it .foo

is being placed in the DOM. This makes the browser think that it was created with opacity: 1

, so no transition is made.

I am wondering if there is an elegant solution for this rather than porting my class to setTimeout.

Here's a snippet:

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

foo.appendTo($('body'));

setTimeout(function(){
    foo.addClass('shown');
});
      

.foo {
    opacity: 0;
    transition: opacity 5s ease;
    width: 200px;
    height: 200px;
    background-color: red;
}

.foo.shown {
    opacity: 1;
}
      

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      

Run codeHide result


+3


source to share


2 answers


In fact, this is not about setTimeout, but about how the element is rendered.

The CSS transition will only appear if the element is rendered with a property value and then that property is changed. But once you are append

an element, it doesn't mean that it has been rendered. Just adding is setTimeout

not enough. Thought it might work for you, in some browser versions it won't work! (Mostly Firefox)

It is about the rendering time of the element. Instead, setTimeout

you can force DOM rendering by querying the visual style property and then changing the class:



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

foo.appendTo($('body'));

//Here I request a visual render.
var x = foo[0].clientHeight;

//And it works, without setTimeout
foo.addClass('shown');
      

.foo {
    opacity: 0;
    transition: opacity 5s ease;
    width: 200px;
    height: 200px;
    background-color: red;
}

.foo.shown {
    opacity: 1;
}
      

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      

Run codeHide result


+9


source


When you do DOM manipulations that this javascript uses right after that, you need to temporarily pause the javascript execution so that the rendering can catch up as this will be done asynchronously. All empty setTimeout does code movement inside the end of the current execution pipeline. The browser has to finish rendering the new layout before it obeys the trigger for your transition, so setTimeout is a good idea and, in my opinion, the most elegant solution.



+1


source







All Articles