Sorry all for so many updates in this question and I'm glad for everyone trying to help me. I think below there is a more clear way to understand this problem:
CSS transitions will not apply if you set the display property of an element to block immediately before changing the property with the transition attached. Consider the following code:
CSS:
#creative {
display: none;
opacity: 0;
transition: opacity 0.5s;
}
HTML:
<div id="creative">
<span>Sample text</span>
</div>
Javascript:
var dom = {};
dom.creative = document.getElementById('creative');
dom.creative.style.display = 'block';
dom.creative.style.opacity = 1;
The element will properly show, but without any transition. A workaround for this problem is to force a repaint by accessing one of the visual properties of the element:
dom.creative.style.display = 'block';
var a = dom.creative.offsetHeight; /* <-- forces repaint */
dom.creative.style.opacity = 1;
is there a good way around this? and by good i mean not adding a extra line of javascript code everytime i need to change the display property and a property with a transition attached.
Based on the code you present in your question I'm going on a completely different way here, and use animation
instead, which will make the whole repaint issue go away
Updated with a script the set the div to display: block
var dom = {};
dom.creative = document.getElementById('creative');
dom.creative.style.display = 'none';
var butt = document.getElementById('button');
butt.addEventListener('click', function(e) {
if (dom.creative.style.display == 'block') {
dom.creative.style.display = 'none';
} else {
dom.creative.style.display = 'block';
}
})
#creative {
display: none;
opacity: 0;
animation: opac 1s forwards;
margin: 20px;
}
@keyframes opac {
100% {
opacity: 1;
}
}
button {
margin: 20px;
}
<button id="button">Toggle display</button>
<div id="creative">
<span>Sample text</span>
</div>
If display: none
is not needed, one can use transition
and simply toggle a class like this
var dom = {};
dom.creative = document.getElementById('creative');
var butt = document.getElementById('button');
butt.addEventListener('click', function(e) {
dom.creative.classList.toggle('show');
})
#creative {
opacity: 0;
transition: opacity 1s;
margin: 20px;
}
#creative.show {
opacity: 1;
transition: opacity 1s;
}
button {
margin: 20px;
}
<button id="button">Toggle display</button>
<div id="creative">
<span>Sample text</span>
</div>
For transition
, besides the offsetHeight
and the setTimeout
solution, there is a 3:rd, having the same visual effect as toggle display block/none, setting the height/width to 0.
var dom = {};
dom.creative = document.getElementById('creative');
var butt = document.getElementById('button');
butt.addEventListener('click', function(e) {
dom.creative.classList.toggle('show');
})
#creative {
width: 0;
height: 0;
opacity: 0;
transition: opacity 1s, width 0s 1s;
margin: 20px 0;
}
#creative.show {
width: 100%;
height: auto;
opacity: 1;
transition: opacity 1s, width 0s;
}
button {
margin: 20px 0;
}
<button id="button">Toggle display</button>
<div id="creative">
<span>Sample text</span>
</div>
<div>Other content</div>
There are no transitions defined for absolute properties, like display. How do you interpolate between none
and block
? You can't. But you can create some post-functions that will run after the animation is done.
You can use setTimeout
and execute some code after the animation is over:
ANIMATION_TIME = 0.5 * 1000; // in ms
function show(element) {
// Display property must be set inmediatly; otherwise, the 'show' animation won't be visible until it ends.
element.style.display = 'block';
element.opacity = 1;
}
function hide(element) {
element.opacity = 0;
setTimeout(function() {
element.style.display = 'none';
}, ANIMATION_TIME);
}
// Call examples
var dom = {};
dom.creative = document.getElementById('creative');
show(dom.creative);
hide(dom.creative);
As @trustk has pointed out, you can also (and preferably) use DOM events:
function show(element) {
element.style.display = 'block';
element.opacity = 1;
element.removeEventListener("animationend", afterHide, false);
}
function afterHide(e) {
// e.target -> element
e.target.display = 'none';
}
function hide(element) {
element.opacity = 0;
element.addEventListener("animationend", afterHide, false);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With