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