Reputation: 1122
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
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
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