yacon
yacon

Reputation: 1122

Transition not working without querying width property

I want to animate a translateX with transition on a click event by adding a class to the div in the js. The transform and transition properties are added in the css file.

var widget = document.getElementById('widget');    
widget.style.display = 'block';
document.getElementById('widget2').clientWidth; //comment this line out and it wont work
widget.className = 'visible';

It only works if I query the width property of any element in the dom before adding the class.

here is a jsfiddle: https://jsfiddle.net/5z9fLsr5/2/

Can anyone explain why this is not working?

Upvotes: 6

Views: 98

Answers (2)

Grüse
Grüse

Reputation: 1175

The issue here is the initial setting of display: none. To the browser's layout manager, this indicates that the layout should be done as if the element in question wasn't even in the DOM (it still is, mind you). This means that the CSS style transform: translateX(-200px); will not be applied.

Doing this:

widget.style.display = 'block';
widget.className = 'visible';

triggers both modifications essentially at the same time - the layout is only re-done after both statements have been executed. Inserting document.getElementById('widget2').clientWidth; (clientHeight works as well) triggers the layout manager to repaint, thus registering transform: translateX(-200px).

As others have mentioned before me, the solution is to either use opacity instead of display (this would be my choice), or to use setTimeout with a delay of 0 (see Why is setTimeout(fn, 0) sometimes useful?).

Upvotes: 0

Passerby
Passerby

Reputation: 10080

That's because you begin your transition and modified the display property "at the same time". Altering display will ruin any transition (citation needed, admittedly), so it would be a good idea to isolate the display changing and actual transiting:

https://jsfiddle.net/5z9fLsr5/3/

document.getElementById('showWidget').addEventListener('click', function(e) {
    e.preventDefault();
    var widget = document.getElementById('widget');    
    widget.style.display = 'block';
    //document.getElementById('widget2').clientWidth;
    window.setTimeout(function(){
        widget.className = 'visible';
    },0);
});
#widget {
    width: 200px;
    height: 80px;
    background: black;
    position: absolute;
    transition: transform 500ms;
    transform: translateX(-200px);
    display: none;
}
#widget.visible {
    transform: translateX(200px);
}



#widget2 {
    position: absolute;
    right: 0
}
<a href="#" id="showWidget">show</a>
<div id="widget"></div>
<div id="widget2">xxx</div>

Querying clientWidth seems to "pause" the execution for some time, so it works too.

Upvotes: 2

Related Questions