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:
If you just add a timeout to the opacity call it should work! The duration can be almost nothing, as long as the display and opacity properties don't get called at the same time.
var dom = {};
dom.creative = document.getElementById('creative');
dom.creative.style.display = 'block';
setTimeout(function(){
dom.creative.style.opacity = 1;
},1);
You can also use a jQuery fadein, if jQuery is an option. Then you can leave out the opacity altogether and just call it like...
dom.creative.fadeIn(500)
You can show / hide element without javascript using css transition only.
<!--html-->
<div id="parent">Some parent text
<div id="creative">Some details</div>
</div>
/*css*/
#parent #creative{
opacity:0;
visibility:hidden;
clip: rect(0px,0px,0px,0px);
transition: all 0.5s;
}
#parent:hover #creative{/*trigger transition*/
opacity:1;
visibility:visible;
clip: rect(0px,220px,0px,330px);
}
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);
}