CodeinWP CodeinWP

Animating from “display: block” to “display: none”

Animating display: block to display: noneAs you might already know, CSS transitions and animations allow you to animate a specific set of CSS properties. One of the properties that cannot be animated is the display property.

It would be great if you could do it, but it’s not currently possible and I’m guessing it never will be (e.g. how would you animate to “display: table”?). But there are ways to work around it, and I’ll present one way here.

Why the Need to Animate “display”?

The need to animate the display property comes from wanting to solve the following problem:

  • You want to make an element gradually disappear visually from the page.
  • You don’t want that element to take up space after it has disappeared (i.e., you want the disappearance to cause reflow).
  • You want to use CSS for the animation, not a library.

For this reason, animating opacity to zero is simply not enough because an element with zero opacity still occupies the same space on the page.

Let’s look at how you might attempt to solve this problem, step by step.

Use Opacity and Display

The first thing you might think of doing is using both the opacity property and the display property. The HTML might look like this:

<div id="box" class="box">
</div>

<button>TOGGLE VISIBILITY</button>

And the CSS might look like this:

.box {
  background: goldenrod;
  width: 300px;
  height: 300px;
  margin: 30px auto;
  transition: all 2s linear;
  display: block;
}

.hidden {
  display: none;
  opacity: 0;
}

Notice I have display: none and opacity: 0 on my “hidden” class. If you toggle this “hidden” class using JavaScript, you might have code that looks like this:

let box = document.getElementById('box'),
    btn = document.querySelector('button');

btn.addEventListener('click', function () {
  box.classList.toggle('hidden');
}, false);

But if you do that, you will not see the transition (defined in the .box declaration block) take effect. Instead you’ll see this :

See the Pen
Trying to Mimic Animating to display:none
by Louis Lazaris (@impressivewebs)
on CodePen.

Click the ‘toggle visibility’ button repeatedly and you’ll see the box disappear and appear suddenly, with no transition.

To fix this, you might try to separate the display property from opacity in your CSS:

.hidden {
  display: none;
}

.visuallyhidden {
  opacity: 0;
}

Then you could toggle both classes:

var box = $('#box');

$('button').on('click', function () {
  box.toggleClass('visuallyhidden');
  box.toggleClass('hidden');
});

But this won’t work, as shown in the demo below:

See the Pen
Trying to Animate to display:none (Part 2)
by Louis Lazaris (@impressivewebs)
on CodePen.

What we want is for the element to disappear visually, then be removed from the page after it finishes disappearing visually, in a manner similar to a callback function.

(As a side point here, even if you combined opacity: 0 with visibility: hidden, it would animate just fine but the element would still occupy space on the page after it disappears, so that won’t work either.)

Why Doesn’t This Work?

Before getting to my solution, I’ll just explain why you can’t do this by just changing the classes one after the other. First, if you’re adding classes like in the examples above, even if the transition worked, you’d have to set up a separate section for removing the classes and reverse how that’s done (i.e. if the box starts out hidden you have to first set it to display: block, then change the opacity).

But that’s beside the point, because it doesn’t work anyhow. JavaScript executes one line after the other, but it doesn’t wait for all things associated with one line to be finished before executing the next line. (In other words, if you execute an animation or other asynchronous event on line 1, line 2 will proceed even if the animation isn’t done).

What’s happening is that the ‘opacity’ is attempting to animate immediately, and even if for a fraction of a millisecond it does start to animate, you won’t see it because the display: none part will take effect just as quickly.

We can sum up the problem we want to solve as follows:

  • When the element is visible, first animate the opacity, then, when that’s finished, make it display: none.
  • When the element is invisible, first make it display: block, then (while it’s still visually hidden, but existing on the page), animate the opacity.

A Possible Solution

There are probably other ways to do this, and I’d be glad to hear how you’d solve this problem. But here is my solution.

The CSS is the same (with the two ‘hidden’ classes still separated), but the JavaScript will look like this:

let box = document.getElementById('box'),
    btn = document.querySelector('button');

btn.addEventListener('click', function () {
  
  if (box.classList.contains('hidden')) {
    box.classList.remove('hidden');
    setTimeout(function () {
      box.classList.remove('visuallyhidden');
    }, 20);
  } else {
    box.classList.add('visuallyhidden');    
    box.addEventListener('transitionend', function(e) {
      box.classList.add('hidden');
    }, {
      capture: false,
      once: true,
      passive: false
    });
  }
  
}, false);

And here it is in action:

See the Pen
Animating from display:none to display:block
by Louis Lazaris (@impressivewebs)
on CodePen.

Here’s a summary of what the code does when the box is visible:

  • Add the visuallyhidden class, which will animate it until it disappears.
  • At the same time that class is added, a single event handler is added using the options object in the addEventListener() method (a new feature with decent browser support), which tells the browser to wait for the transitionend event to occur once, then it stops looking.
  • The transitionend event fires when the opacity is done animating, and when this occurs the element is set to display: block.

Because you can’t detect a transitionend event on the display property, you have to use a different method for when the box is invisible:

  • First remove the hidden class, making it display: block while it’s still visually hidden.
  • While this is occuring, the script has executed a delay using setTimeout(), after which the opacity begins to animate.

The delay is very small (20 milliseconds), but because display: block occurs instantly, you don’t need much of a delay at all, just enough to allow the element to take its full place on the page before animating the opacity. You might have to mess around with the timing in some cases, possibly going down to as little as a single millisecond.

And in case you want to start with a box that’s hidden and make it appear, you just have to ensure that both the hidden and visuallyhidden classes are on the box when it starts. Here’s a demo:

See the Pen
Animating from display:none to display:block
by Louis Lazaris (@impressivewebs)
on CodePen.

If you don’t include both classes, the initial appearance won’t be animated.

How Would You Do It?

As mentioned, there are probably other ways to do this, or maybe there’s some improvement that could be made to my code.

Personally, I feel the use of setTimeout is a bit lame and hacky. But hey, it works, and I don’t think it’s going to cause any problems unless you had tons of similar animations on the page. But that would be another issue altogether.

There are a few possible solutions to this on StackOverflow, but I find most, if not all, of the proposed solutions don’t really solve the problem at hand.

Feedback is welcome.

107 Responses

  1. I usually avoid display:none and use instead transform:translate(9999px);

    .box {  
      transition: opacity 2s linear;  
      transform:translate(0);
      opacity: 1;
    }  
    .hidden {  
      transform:translate(9999px);
      opacity: 0;  
    }
    
    • Yes, but that doesn’t solve the problem of removing the space occupied by the original element. Also, in your example, I don’t think you’d see the animation, because the translate transform would occur instantly, removing it from view.

    • Cody says:

      My good sir you are a genius.. glad i scrolled to the comments this saved me a lot of headache. Thumbs up

      • Stan says:

        That is wrong. If you attempt to hide an intractable component like that you can still access it via assistive technology. This does not lead to a good product.

    • Sérgio says:

      Well. You’re doing it wrong. You should avoid moving the element far away. that is a very ugly hack.

    • Minks says:

      I used to think that way I don’t used display: none, and display: block, I hide the element in terms of width and height, not knowing that the element is still visible in the document, and this effect harms accessibility.

      Though visually, we we’re able to hide the element but in terms of accessibility, the element is still visible. We imagine that we hide elements only for visual users, however for visually impaired users, user using screen readers, the element is visible for them. In this case, we harm their experience.

      So therefore using display: none and display: block is essential, you may encounter this in creating responsive navbars as an example. When the breakpoint reach mobile view we need to hide the navbar and show the toggle menu button, we may use to set height or width to 0 but the navbar is visible in the document.

      By displaying it to none, we can assure that it’s not visible at the moment until the user toggles’ the menu button, which provides better experience not only for visual users but including visually impaired users.

  2. Kalley Powell says:

    What if you did something like the following: http://jsbin.com/IBumuMo/1/

    Using step-start and step-end opens up a few other possibilities.

  3. Jon Christensen says:

    How about a delay when the hidden class is added and no delay when removed?

    .box {
      opacity: 1;
      transition: opacity 1s, height 0;
    }
    
    .hidden {
      opacity: 0;
      transition: opacity 1s, height 0 1s;
      height: 0;
    }
    
  4. Chris says:

    JavaScript executes one line after the other, but it doesn’t wait for one line to be finished before executing the next line.

    This is not true at all. JavaScript statements are not asynchronous, although they can invoke asynchronous behavior in other libraries. You may be referring to jQuery transitions here (which are asynchronous) but as written this statement is false. If JavaScript did not guarantee complete execution of one statement before executing the next, the language would be effectively useless.

    • Ah, you’re right. What I’m trying to say is that if the previous line contains an asynchronous event, then it will not wait for that one to finish (in this case, I’m referring to the result of the class being added/removed, which causes asynchronous events to occur). I’ll correct the wording.

  5. How a bout keyframes?

    Where the 0% would set the display property and the 1% – 99% do the opacity and 100% does the display again. ;-)

  6. Andrei Pham says:

    Umm, I believe that what you did isn’t enough. Just like you said, when setting display: none on an element, it doesn’t just fade away. It also disappears and the page acts like the element weren’t there. So theoretically, you should animate the “disappearing” thing too, not just the opacity. And this means that after fading it away and before setting display: none to it, you should set the height to 0px smoothly (or width if content flow is horizontal).

    • I’ve updated my codepen to reflect that, I think that works better indeed.
      Width and height are optional of course, depending on what you want animated.

    • I agree, from a visual standpoint, it’s probably jarring to see the content around flow into a new area so suddenly. So yes, you could animate height or width. That’s just one way to do it. And I think you’d also need to do “overflow: hidden” if you use that, depending on what’s inside the element.

      But if you use height, then you have to have a specified height for the element, which is unlikely. Usually content dictates height. And you can’t animate to “height: auto”, so that’s not always an option. Of course there are workarounds for that too, but again, they always have some drawbacks.

      • To solve this in the past I’ve just animated min-height: property. If you have a rough idea of the general height it would have you can get away with using that to hide it.

  7. Roman V says:

    If in the end you use so much JS, why would you not go for something like $(‘.box’).fadeToggle() ?

    • Because I want to use CSS animations, which generally the browser can optimize better. But probably in a case like this, using it one or two times wouldn’t matter. The idea is to try to get away from jQuery animations, leaving the animating part to CSS where I believe it is more appropriate.

  8. Paul O'B says:

    Hi,

    Nice article Louis.

    It’s a shame that you can’t animate from height:auto to height:0 as usually that is what you want. However, if you need a fluid height then don’t use height but use max-height instead although you can’t actually animate the height you can create a decent fade effect and remove the element from the flow.

    Here’s a codepen:
    http://codepen.io/paulobrien/full/tpmAi

    It’s not perfect but can be useful in certain situations and needs no JS in modern browsers (using the :checked pseudo class instead).

  9. IMO playing with delays is the way to go. So you can combine opacity and top properties, which means our “fadeable” elements are always printed but they are offscreen.

    If you absolutely need to support ie8 then you’d use opacity + top properties:

    .elem {
      top:-2000px;
      opacity:0;
      transition: opacity .3s ease 0s, top 0s linear .9s;
    }
    
    .visible {
      top:0px;
      opacity:1;
      transition: top 0s linear 0s, opacity .3s ease .01s;
    }

    And if you don’t care about oldies, then you can go with opacity + translateY properties. This way is surely the best possible because your element gets uploaded to the GPU (translate property) and so you’ll get the lowest possible repaint cost. It could look like this:

    .elem {
      transform: translateY(-2000px) translateZ(0);
      opacity:0;
      transition: opacity .3s ease 0s, transform 0s linear .9s;
    }
    
    .visible { 
      transform: translateY(0px);
      opacity:1;
      transition: top 0s linear 0s, opacity .3s ease .01s;
    }

    Of course I omitted all the vendor prefixes in these little snippets.
    Grunt (or Brunch) Autoprefixer FTW

    • In both those examples, you’re not really solving the problem I outlined at the beginning. In the case of both “top” and “translate”, the element is still going to take up the same amount of space on the page, so it will not cause reflow.

      Your solution is fine if you want to just fade an element out, and don’t care about reflow. But if you want the original occupied space to be gone, then you have to use another method. For details on what I’m talking about, see this post:

      http://www.impressivewebs.com/css-things-that-dont-occupy-space/

  10. Cristian says:

    Playing with paddings and height works pretty fine to emulate the desired display effect: http://jsfiddle.net/catharsis/n5XfG/17/

  11. Chris says:

    How about scaleX(0.00001) as hidden state, then scaleX(1) as visible state, then couple that with opacity:0, opacity:.999 and transition both. scaleX(0.00001) gets the element out of view, like a better visibility: hidden, but uses hw acceleration.

    • Again, that would work fine in many circumstances, but not in the scenario I’ve presented in this post (which is, admittedly, not that common). As I mentioned to others, and in the article, stuff like transforms and opacity make things invisible but they don’t cause page reflow. In other words, if an element is 200×200 in size, if you shrink it down using scaleX/Y, it will still take up 200×200 pixels in space on the page.

      The only way to do what you’re saying is to add “position: absolute” to the element, which takes it out of the flow. So I wonder if that would work better like that…. might be worth experimenting with.

      • Chris Wigley says:

        Ah yes, I was assuming the element would be positioned absolute. I use the scale(0.0001) technique and it works well — for elements that are absolutely positioned.

  12. check_ca says:

    If you need a reflow, then you should read a property which triggers it (e.g. “offsetWidth”). Here’s an eample:

    box.removeClass('hidden');
    box.prop("offsetWidth");
    box.removeClass('visuallyhidden');
    
  13. Elmira says:

    We could also do this animation without any JQuery or javascript by only css properies.
    Some browser in client computers are javascript disabled for security reasons. So I think
    that would be beneficial if you could also mentioned making animation with css only too.

  14. I worked around the display none/block limitation by using height 0 like the earlier comments above. Needed to play an animation then remove it afterwards:

    .item-to-animate {
      height: 0;
      animation: some-animation
    }
    
    @keyframes some-animation {
      0%, 100% {
        height: auto;
      }
      0% {
        /* start animating stuff */
      }
      99.99999% {
        /* end animating stuff */
      }
    }
    
  15. InfinPixels says:

    We often use JQuery because it is possible to make pages more user friendly and fun. Thanks for the useful tutorial.

    Serkan

  16. sachin Tendulkar says:

    Thanks for the useful tutorial.

  17. Pabzt says:

    this is what i use:

    I style my element in a way i want to display it and add display:none:

    #menu {
     display: none;
     /* other styles... */
    }
    

    Then I create a keyframe animation

    @keyframes animation{
      0% { opacity: 0; }
    
      100% {opacity: 1;}
    }
    

    Add a class for the animation

    .someClass {
      animation-name: animation;
      animation-duration: 0.1s;
      animation-iteration-count: 1;
      animation-timing-function: ease-in;
    }

    I created a jquery function to handle display none which gets the timeout from the animation class and also has a callback function for after animation stuff…

    $.fn.css3In = function(a, args) {
      return this.each(function() {
        $(this).css('display', 'block').addClass(a);
        var duration = $('.' + a).css('animation-duration');
        duration = duration.substring(0, duration.length-1) * 1000;
    
        var object = $(this);
        
        setTimeout(function() {
          
          $(object).removeClass();
          args.AnimationEnd();
    
        }, duration);
    
      });
    }
    

    Then I’m able to use any css3 Animation with keyframes on any object that has display none

    
    $('#menu').css3In('someClass', {
      AnimationEnd:function() {
        // Do Something after animation
      }
    });
    

    from display block to display none i use another jQuery function that does basicly the same:

    
    $.fn.css3Out = function(a, args)
    {
      return this.each(function()
      {
        console.log("out animation running...");
        $(this).addClass(a);
        var duration = $('.' + a).css('animation-duration');
        duration = duration.substring(0, duration.length-1) * 1000;
    
        var object = $(this);
    
        setTimeout(function() {
          
          $(object).removeClass();
          $(object).css('display', 'none');
          args.AnimationEnd();
    
        }, duration);
    
      });
    }
    
  18. Alvin says:

    Very nice tutorial!
    is it possible to animate the button to slide up after the box’s animation?

  19. Lurker says:

    You may use ‘pointer-events:none’ with opacity to achieve the effects but with some fallback in >IE10.

  20. Eva says:

    we always look for nice transition techniques like this one. Thank you for the idea.

  21. Sérgio Santana says:

    A beter way i thing

    div.yourclass{


    height: 0;
    transition: opacity 0.3s

    }

    div.yourclass:hover{

    height: 200px;

    }

    that code make just de opacity has transition :)

  22. Danny says:

    Thanks for the useful article, it works perfectly.

  23. Ahsan says:

    Well if I have to still use JavaScript… Why not use jQuery fadeIn and fadeOut function

    • Yep, that’s the simplest way, but the idea here was to try to figure out a way to do it with CSS performing the actual animation.

      And if I wrote this today, I’d probably avoid jQuery and use plain JS.

  24. David Waters says:

    Stumbled across this article with a similar problem. My solution is a little different from what I’ve seen and I’m cutting my teeth on JS.

    I wrapped the hidden content in a div with ‘overflow: hidden’ and set its height to 1px (so I can calculate the height of the hidden content). When the click triggers, I set the wrapper height to the content’s height and fade in the content.

    This way, CSS height animations still work, since the pixel value is set.

  25. Aamir Suleman says:

    I would change the absolute position to be offscreen when the hidden class is applied

    .hidden {
      opacity: 0 !important;
      top:-1000px !important;
    }
    
  26. Odin says:

    Hey, I really need help making this method work the other way around. So the initial div is hidden and by clicking a button I want it to fade in and then fade out (toggling). I want to use the method for an overlay menu.

    Can you help me tweak the code?

    • Can you provide a demo of what you have so far? Also, doesn’t my final demo do exactly what you just said? I’m not sure what exactly you require beyond that. You might have to be more specific.

      • Odin says:

        Ok, so, in your demo the div which the effect is applied on is initially visible whereas in my example the div is initially hidden. Imagine that I need to apply it on an overlay menu of a website and obviously on a website usually the overlay menu (which occupies the whole viewport) is initially hidden and then if you click a button (in my case the classic hamburger icon) it opens(fades in) and if you click it again it closes(fades out) and so on.

        Conclusion: I basically need what your demo does but the other way around (from hidden to visible to start with instead of from visible to hidden to start with).

        I managed to make it work by doing a workaround manually adding both classes “visuallyhidden” and “hidden” on the overlay menu div to start with. Example.

        <div id="menu_wrapper" class="hidden visuallyhidden">
          <!-- Menu Content Here-->
        </div>

        This is how I have the code in the HTML page to start with (it works) but.. I best believe this is not a best practice. I was wondering how do I tweak the code to make it work strictly with jQuery and CSS without manually adding “visuallyhidden” and “hidden”.

        Let me know if this makes sense and if you still need me to provide a demo. Thanks a ton!

        • Based on my code from this article, what you’ve done is correct. That’s basically the only way to do it. Now, that being said, this is a bit of a hacky solution. But if that’s what you want, then yes, you just have to adjust the HTML classes so that it starts hidden.

          • Odin says:

            If it requires a whole new function then I’ll just leave it as is. I tried manipulating the code but I couldn’t accomplish anything in my favor. I tried switching the classes from visuallyhidden to visuallyshown with "opacity:1" and hidden to shown with "display:block", I added "display:none" to the #menu_wrapper but I always ended up with the the function adding the visuallyshown class but not the shown class and then the function fell apart.

            Thanks again for the quick reply and keep up the great work!

  27. rsm says:

    Thanks for the post, I was able to create my own javascript for my website!

  28. Fred says:

    I typically use css transition on max-height, which allows for a sliding open/close of an element.

  29. Amod Oke says:

    How can I use this to “show” a div instead of using toggle.
    Meaning I have this layout:

    <div class="1">First div</div>
    <div class="2">Second div</div>
    <div class="3">Second div</div>
    <div class="4">Second div</div>
    

    I already have a script that ‘fades in’ the opacity to show the divs as a user scrolls to it, but I want to hide them with display:none so that the browser’s scroll bar looks small initially…

    … so when the user scrolls to the concerned div, only then it shows up and ‘adds’ to the scroll bar.

    Here is my demo of the scrolling opacity toggler:
    https://output.jsbin.com/civuqu/edit</a.

  30. Pawel says:

    Try this:

    var checkDisplay = function() {
      if($('.your-selector').css('display') !== 'block') {
        setTimeout(checkDisplay, 10);
      } else {
        $('.your-selector').addClass('class-with-opacity-1');
      }
    };
    checkDisplay();
  31. Tim says:

    Thanks for sharing! I was getting obscure issue with the content on iOS. Was working on my Android phone though (ie. content that was set to opacity: 0 and visibility: hidden)

  32. IniCou says:

    The below combination of JQuery’s “addClass & removeClass” (or Angularjs’s “ng-class”) along with the CSS @kayframe animation works perfectly for me in Chrome browser (did not check with other browsers)

    <style>
    @keyframes showIn {
      from { opacity: 0; }
      to   { opacity: 1; }
    }
    .myElement {
      display: none;
      color: #ddd;
      background: #000;
      width: 200px;
      padding: 24px;
      margin: 0 auto;
    }
    .myElement.fadeIn{
      display: block;
      animation: showIn 1s ease-in forwards;
    }
    </style>
    <div ng-model="showMyElement" ng-init="showMyElement=false" style="padding:30px">
      <p class="myElement" ng-class="{'fadeIn':showMyElement}">Click the below [button] to display an HTML element animatically</p>
      <button ng-click="showMyElement = !showMyElement">Click To <span ng-if="!showMyElement">Show</span><span ng-if="showMyElement">Hide</span></button>
    </div>
    
  33. Type-D says:

    Hmm, isn’t it easier to just use “position: absolute” on the element so it doesn’t take up any space? You can also place it in another container if you like. So something like in CSS:

    #container {
      position: absolute;
      left: 200px;
      top: 200px;
    }
    .inner-item {
      position: absolute;
      top: 0;
      left: 0;
      opacity: 0;
      transition:opacity 0.5s linear;
    }
    .inner-item.active {
      opacity: 1;
    }
    

    HTML:

    So every time you change the active element, it does the trick:

    $("div#container>div.inner-item.active").removeClass("active");
    $("div#container>div.inner-item:nth-child([index you want to activate])").addClass("active");
    
  34. Clay says:

    So this won’t work for everyone, but it solved my problem.

    I wanted to hide links in the header when scrolled by adding a class with a css animation attached to it. I was able to hide the link by setting opacity to 0 but users could still click on it if they hovered over it. So, I just set the font size to 0 as well so the links wouldn’t show up, and wouldn’t take up any space. This only works with text obviously, but I’m thinking setting the height to 0 may produce a similar effect. The css looked like this:

    @keyframes fade-out {
      0% {opacity: 1; font-size: 1em;}
      100% {opacity: 0; font-size: 0;}
    }
    
    .header-link-fade {
      animation-name: fade-out;
      animation-duration: .4s;
      animation-iteration-count: 1;
      animation-fill-mode: forwards;
    }
    

    Then I just toggled the class with jQuery with the link selector:

    $(window).scroll(function() {
    
      var scrollTop = $(this).scrollTop();
      $(".header-link-selector").toggleClass("header-link-fade", scrollTop>20); 
    
    }).scroll()
    
  35. JP says:

    The link to Christian Heilmann’s solution is broken. Here is the correct link:
    https://christianheilmann.com/2015/08/30/quicky-fading-in-a-newly-created-element-using-css/

  36. Evgeny says:

    Great post! Thank you so much!

  37. Amaury says:

    Thank you very much, it’s work great for me :)

  38. Qube says:

    I just used width: 0; overflow: hidden; on element when hidden and width: 100%; when visible

  39. Felip says:

    Hello everybody,

    I like the initial idea about dispplay:none, and i found a way to use it in addition to use a fade with opacity. It’s based on a listener to know when an element has ended its transition.

    I use this:

    #loadingWrapper {
      width:100vw; 
      height:100vh; 
      z-index:1000; 
      position:absolute; 
      top:0; 
      left:0; 
      transition: all 1s ease-out;
      opacity:1;
    }
    
    function loadingWrapperOut() {
      document.getElementById("loadingWrapper ").style.display = "none";
    }
      
    window.addEventListener("load", () => {
     document.getElementById("loadingWrapper ").addEventListener("transitionend", loadingWrapperOut);
     document.getElementById("loadingWrapper ").style.opacity = "0";  
    });
    
  40. Rick says:

    Hi,

    Great post and a lot of useful comments.

    Wonder if anyone could help me? So I have taken one of the solutions and trying to make it hide a div but the button stay where it is and not slide with the hidden div.

    Here is a fiddle of it:

    https://jsfiddle.net/Rick1107/resu6cqx/1/

    Any help will be gratefully appreciated.

    • If you want the button to stay there, then you have to change the hiddenContent section to be like this:

      .hiddenContent {
        opacity: 0;
      }
      

      You have to remove the height and margin. But I’m not sure if that’s what you want, because your comment wasn’t that clear.

      • Rick says:

        Thanks Louis. Very much appreciated you understood my poor question perfectly and yes thats exactly what I wanted. Thank you!

  41. J says:

    Why not just set height and width to 0 on the element that has visibility:none? Not perfect, but it won’t take up any room on the screen and will allow transitions.

  42. میلاد (Mila) says:

    Generally when people are trying to animate display: none what they really want is:

    Fade content in, and
    Have the item not take up space in the document when hidden
    Most popular answers use visibility, which can only achieve the first goal, but luckily it’s just as easy to achieve both by using position.

    Since position: absolute removes the element from typing document flow spacing, you can toggle between position: absolute and position: static (global default), combined with opacity. See the below example.

    .content-page {
      position:absolute;
      opacity: 0;
    }
    
    .content-page.active {
      position: static;
      opacity: 1;
      transition: opacity 1s linear;
    }
    

    source:
    https://stackoverflow.com/questions/38772442/css-transition-from-display-none-to-display-block-navigation-with-subnav/38772750

  43. Daniel Flego says:

    How bout in reverse, starting with the display: none; then display: block.

    • The final demo on the page does that when you click the button a second time.

      • Daniel Flego says:

        I mean starting with nothing then appearing, like as in a drop down box style if that makes sense. I tried reversing some of the properties around(like putting the box values in the hidden and visa versa and adjusting the js) but it doesn’t seem to register in the same way.

        I’m making a header with a toggle button in it that when clicked has a unordered list with a bunch of lists in it appear underneath the header that display the menu.

        I’ve got it all working I just want to add a sliding transition effect as the unordered list appears.

        • That’s not exactly what this code in the article is about. Maybe if you send me a CodePen demo or something, then I can help, but this article is attempting to solve a specific problem.

          Your issue is just making something slide down, which is just a matter of adding some CSS and JS similar to what jQuery animations do.

  44. imaniy says:

    Can you advise how to hide that yellow box by default and show it by pressing the button?

  45. Krushnakant says:

    I want to apply this animation in Table of Contents but it does not work well. the transition was not showing properly. are you have any other method to show the transition.

  46. Daniel says:

    There is an example by Marco Peralta at CodePen. I mixed it up with your’s, to eliminate the setTimeout() function.

    https://elnet.ch/de/test/display-none

    • This is a good solution. If I were to write this solution today, I would definitely do what you’ve done, using the transitionend event along with the once option for addEventListener which I don’t believe existed when I first wrote this article.

  47. Josh says:

    Couldn’t you use setTimeout in both appearing and disappearing? That is, if you set the transition to a certain interval in CSS, then can’t you just set your JS with the same interval (or a fraction longer)? It is interesting to use the transitionend listener, though. Thanks for the illustration of that event listener.

  48. Aida says:

    Works just fine, I just change the transition for smooth transition
    transition: display 1s, opacity 500ms ease-in-out;

  49. Kevin says:

    Your method is not a good solution when you have multiple transitions or if you want to change the timing of the transition.So I just inspected the YouTube page and found their secret.The secret life saver is “visibility” property.Their method is to add one extra element prior to the element you want to apply transitions .Then set the “display” property of all other elements after that to “block” or whatever you want but don’t set it to “none”.Now you can transition the “visibility” property of the extra element instead of transitioning the “display” property.Now you can add or remove classes from other elements when the button is pressed.They will be automatically transitioned without any problem.When you want to show the element set the “visibility” to “visible”.When you want to hide the element set the “visibility” to “hidden”.This works fine both in displaying and hiding a element.

  50. SFay says:

    the first 3 suck its the same animation- the last one is good-
    But why all this code for nothing?

  51. Hello, how can i implement that it is initially hidden at first and it can be shown at first click. I tried putting hidden in class first but it does not animate. Thank you

    • Good question! I added a new demo to demonstrate how to make that work. It turns out, you just have to add both of the hidden and visuallyhidden classes to the box to begin with, but the rest of the code stays the same.

  52. Parkle says:

    Thanks for the detailed blog post. I wrote a library called Onion to address this exact problem, please check it out at https://www.npmjs.com/package/onion and let me know what you think!

  53. HeavyLogic says:

    For all who hates jQuery:
    $('.element').fadeOut(300);

  54. Jimmy says:

    Thanks for the post! I’ve been hunting for a solution too, and this is the best alternative I found that is pure CSS, feels less hacky, and works a treat for my use case:
    https://jdsteinbach.com/css/snippet-animate-display-transform/

    …at least until this becomes more widely adopted across vendors: https://developer.chrome.com/blog/entry-exit-animations

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).