title: Fade In without jQuery (fadeIn) - CSS transition opacity and display
body: <p>I'm trying to implement an effect identical to jQuery's <code>fadeIn()</code> function, where an element is displayed, and then it's opacity is animated from 0 to 1.  I need to do it programmatically (WITHOUT jQuery), and I need the element to be able to fade out (<code>display:none</code>) and then fade back in.  </p>
  
  <p>The ideal solution will use a CSS transition to leverage hardware acceleration - I can get the element to fadeOut with great success by listening to the <code>transitionend</code> event.  Fading back in, however is proving to be a challenge as the following bit of code is not working as intended:</p>
  
  <pre><code>fader.style.transition = 'opacity 1s';
  
  const fadeIn = () =&gt; {
    fader.style.display = 'block';
    fader.style.opacity = 1;
  };
  </code></pre>
  
  <p>When <code>fadeIn()</code> is called the element simply snaps back in, instead of smoothly animating.  I have a <a href="https://codepen.io/shanepoints/pen/zgqvOa" rel="nofollow noreferrer">codePen that I've been tinkering with</a> to illustrate the problem.</p>
  
  <p>My theory is that the transition is unable to execute on an element that's not in the DOM, as I can get the animation to work by setting <code>height:0</code> instead of <code>display:none</code>.  Perhaps there is a delay between when I set <code>fader.style.display = 'block';</code> and when the DOM is actually being updated, during which I cannot transition?  </p>
  
  <p>On that idea: I also seem to be able to get the animation to work by delaying the opacity change with <code>setTimeout(() =&gt; {fader.style.opacity = 1}, 20}</code>.  This seems to create a sort of race condition however because as the timeout duration gets closer to 0 the animation works less and less dependably.</p>
  
  <p>Please note that I do not want to toggle the <code>visibility</code> attribute like the solutions to <a href="https://stackoverflow.com/questions/3331353/transitions-on-the-display-property">this question</a>, as that does not effectively remove the element from the DOM. </p>
  
  <p>Changing the height/width to 0 is a more viable option, but because the height and width of the element are not known, it will require the extra step of capturing those values before fading out so they can be re-applied when fading in. This seems flimsy if, say, a different part of the application tries to change those values (for example a media query, and the user rotates their device while the element is hidden)</p>