@Jawad: Only if you add something like z-index:0 as well.
– DanManOct 31 '12 at 9:52

4

@Jawad: It's recommended to never use visibility: hidden unless you want screenreaders to read it (whereas typical browsers won't). It only defines the visibility of the element (like saying opacity: 0), and it's still selectable, clickable, and whatever it used to be; it's just not visible.
– Forest KaMay 19 '13 at 23:14

1

no support for pointer-events in IE 8,9,10, so it's not always ok
– Steven PribilinskiyFeb 20 '15 at 14:08

This answer seems like less work than the others and achieves what we would expect from display:none/block; Thanks. Saved me a ton of time.
– BrendanAug 28 '12 at 19:16

19

Yeah the problem with this is anything behind it will overlap even if it's not visible. I found using height:0 a much better solution
– Josh BedoSep 2 '13 at 23:34

601

This is nice but the problem is that "visibility hidden" elements still occupy space while "display none" does not.
– Rui MarquesNov 14 '13 at 10:48

31

I'm probably missing something, but why do you alter both the visibility AND the opacity? Won't setting the opacity to 0 hide the element - why do you need to set the visibility to hidden too?
– GMAJul 3 '14 at 11:14

13

@GeorgeMillo if you set only the opacity, the element is actually still on the page rendering (you can't click thought for example).
– GrsmtoAug 26 '14 at 19:37

Thanks Jim for a thorough answer. You're absolutely right about the fact that if the display: property changes at all, then ALL of your transitions will not work. Which is a shame - I wonder what the reasoning behind that is. On a side note, on the same link I posted in the original question, you can see where I'm at with it. The only (small) problem I have is in Chrome [5.0.375.125] when the page loads, you can see the menu quickly fading away as the elements are loaded on the page. Firefox 4.0b2 and Safari 5.0 are absolutely fine... bug or something I've missed?
– RichardTapeJul 28 '10 at 19:45

7

I agree that this is right on and will contribute this; a heads up for future travelers. I found a working solution in Chrome, but I found it fails on iPhone 4: visibility:hidden; opacity:0; -webkit-transition: all .2s ease-in-out; Not only does this not transition correctly, but the target element will never show up. QA will fail you, me, and your mom.
– SimplGyApr 5 '11 at 19:37

1

You can actually transition the visibility property as well.. just saying
– Cu7l4ssDec 8 '12 at 21:10

1

If you set your hidden state to height: 0; and don't transition it, the transition will not work. I tried this just trying to transition opacity. I had to remove the height: 0;
– chovyJun 27 '13 at 0:00

6

you've just won a vote up because of the overflow: hidden thank you a lot!
– thiagohDec 18 '15 at 14:33

Thanks for this. The height: 0 trick (for transitions) mentioned above doesn't seem to work because the height gets set to 0 on the fade-out transition, but this trick seems to work just fine.
– Elliot WinklerMar 14 '12 at 20:42

41

Thanks, very useful. But how to fade it out?
– IlliouOct 15 '12 at 2:37

1

The first paragraph of this answer doesn't quite make sense. Browsers don't just disable all transitions outright the moment you use the display property - there is really no reason to. And even if they did, why would animations work then? You can't use the display property in CSS animations either.
– BoltClock♦Jul 11 '14 at 10:17

5

Best answer, not possible with transitions but yes with animations.
– MikelMar 24 '16 at 15:13

5

How about reverse animation, that is when element should slowly disappear?
– GreenMay 23 '16 at 6:57

I suspect that the reason that transitions are disabled if “display” is changed is because of what display actually does. It does not change anything that could conceivably be smoothly animated.

“display: none;” and “visibility: hidden;” are two entirely different things. Both do have the effect of making the element invisible, but with “visibility: hidden;” it’s still rendered in the layout, but just not visibly so. The hidden element still takes up space, and is still rendered inline or as a block or block-inline or table or whatever the “display” element tells it to render as, and takes up space accordingly. Other elements do not automatically move to occupy that space. The hidden element just doesn’t render its actual pixels to the output.

“display: none” on the other hand actually prevents the element from rendering entirely. It does not take up any layout space. Other elements that would’ve occupied some or all of the space taken up by this element now adjust to occupy that space, as if the element simply did not exist at all.

“display” is not just another visual attribute. It establishes the entire rendering mode of the element, such as whether it’s a block, inline, inline-block, table, table-row, table-cell, list-item, or whatever! Each of those have very different layout ramifications, and there would be no reasonable way to animate or smoothly transition them (try to imagine a smooth transition from “block” to “inline” or vice-versa, for instance!).

This is why transitions are disabled if display changes (even if the change is to or from “none” — “none” isn’t merely invisiblity, it’s its own element rendering mode that means no rendering at all!),

This is correct. It's not immediately obvious, but once you do think about it, it doesn't take long for you to realize that transitioning the display property couldn't possibly work.
– BoltClock♦Jul 11 '14 at 10:20

4

As good as the above solutions might be, it was very satisfying to get a sensible explanation as for why transitions don't apply to display attributes.
– kqrSep 17 '14 at 14:27

8

I disagree. It could make complete sense. If display:none to display:block occurred instantly at the start of the transition, that would be great. And for transitioning back, if it went from display:block to display:none right at the end of the transition, that would be perfect.
– Curtis YallopJun 2 '15 at 17:08

1

If you can't imagine what an animation from a point to a rectangle looks like, you've got problems. A transition from occupying no space to occupying a rectangular space is VERY obvious, like, you do it every time you drag a rectangle out with the mouse in like every application ever. As a result of this failure, there are so many hacks involving max-height and negative margins it's rediculous. The only thing that works is caching the 'real' height and then animating from zero to the cached value with JavaScript. Sad.
– TriynkoMar 16 '17 at 2:36

1

Tryniko : display:none does not change the size of the element to a rectangle of 0 x 0 - it removes it from the DOM. You could animate from a rectangle to a point by animating the width and height properties to zero and then the other elements would flow around it as if it had 'display:none' but its 'display' attribute would remain 'block'; the element is still in the DOM. The concept of animating between display:block and display:none is ridiculous : There are no intermediate states. An element either exists in the DOM or it doesn't, no matter how small or invisible it is.
– Steve ThorpeMay 7 '17 at 1:42

Last time I had to do this, I used max-height instead, which is an animatable property (although it was a bit of a hack, it did work) but beware that it may be very janky for complex pages or users with low-end mobile devices.

The correct transition for something that occupies no space (as is the case with display: none) to something that occupies space (display: block), is an expansion of dimensions, not a fade-in. If it were a matter of visibility hidden (which occupies space but is not visible) to visible, then the size stays the same and a fade-in is appropriate. None of these answers solve the problem.
– TriynkoMar 16 '17 at 2:42

@Alex Ok. Typo fixed. What's interesting is that my answer doesn't even work as expected, but it's logical to think that it would so I'll keep it until browsers will support it.
– PawelMar 14 '16 at 15:13

I ran into this today, with a position: fixed modal that I was reusing. I couldn't keep it display: none and then animate it, as it just jumped into appearance, and and z-index (negative values, etc) did weird things as well.

I was also using a height: 0 to height: 100%, but it only worked when the modal appeared. This is the same as if you used left: -100% or something.

Then it struck me that there was a simple answer. Et voila:

First, your hidden modal. Notice the height is 0, and check out the height declaration in transitions... it has a 500ms, which is longer than my opacity transition. Remember, this affects the out-going fade-out transition: returning the modal to its default state.

Second, your visible modal. Say you're setting a .modal-active to the body. Now the height is 100%, and my transition has also changed. I want the height to be instantly changed, and the opacity to take 300ms.

You could also use height in place of max-height if you specify both values since height:auto is not allowed with transitions. The hover value of max-height needs to be greater than the height of the menu can possibly be.

It's a nice trick but there's a shortcoming. The transition time depends on the height. If there are multiple menus with variable height, those elements with height closer to max-height would animate nicely. However the shorter ones would animate too fast, giving an inconsistent experience.
– userFeb 14 '16 at 8:00

After the accepted answer from Guillermo was written the CSS
transition Spec of 3 April 2012 changed the behavior of the visibility transition
and now it is possible to solve this problem in a shorter way, without the use of
transition-delay:

W.r.t. the title of the question "Transitions on the display: property" and
in response to comments from Rui Marques and josh to the accepted answer:
This solution works in cases where it is irrelevant if the display or
visibility property is used (as it probably was the case in this question).
It will not completely remove the element as display:none, just make it
invisible but it still stays in the document flow and influences the position of the following elements.
Transitions that completely remove the element similar to display:none can be done
using height (as indicated by other answers and comments), max-height, or margin-top/bottom, but also see
How can I transition height: 0; to height: auto; using CSS?
and my blog http://www.taccgl.org/blog/css_transition_display.html.

In response to comment from GeorgeMillo:
Both properties and both transitions are needed: The opacity property
is used to create a fade-in and fade-out animation and the visibility
property to avoid the element still reacting on mouse
events. Transitions are needed on opacity for the visual effect and on
visibility to delay hiding until the fade-out is finished.

I suspect anyone just starting CSS transitions quickly discovers that they don't work if you're modifying the display property (block/none) at the same time. One work-around that hasn't yet been mentioned is that you can continue to use display:block/none to hide/show the element, but set its opacity to 0 so that even when it's display:block, it's still invisible. Then to fade it in, add another CSS class such as "on" which sets the opacity to 1 and defines the transition for opacity. As you may have imagined, you'll have to use JavaScript to add that "on" class to the element, but at least you're still using CSS for the actual transition.

P.S. If you find yourself in a situation where you need to do both display:block, and add class "on", at the same time, defer the latter using setTimeout. Otherwise the browser just sees both things as happening at once and disables the transition.

No javascript required, and no outrageously huge max-height needed. Instead, set your max-height on your text elements, and use a font relative unit such as rem or em. This way, you can set a max height larger than your container, while avoiding a delay or "popping" when the menu closes:

If you want to animate the element moving from display block to display none, I can't see that it is currently possible just with CSS, you have to get the height and use a CSS animation to decrease the height. This is possible with CSS as shown in the example below, but it would be tricky to know the exact height values you need to animate for an element.

Explanation: it uses the visibility: hidden trick (which is compatible with “show-and-animate” in one step) but uses the combination position: absolute; z-index: -1; pointer-events: none; to make sure that the hidden container does not take space and does not answer to user interactions.

But the change of position still will make the element jerk around, no?
– ArsylumFeb 18 '18 at 17:31

Well, off course: position: absolute means that the element doesn't take any space, as described in the explanation. When it switches to position: static and appears, it will take space like a normal element, which is the point of this question. I suggest you try it!
– Christophe MaroisFeb 19 '18 at 15:49

2

I did. But if I understand right the question was about transitions. As in "smooth animations".
– ArsylumFeb 19 '18 at 21:50

By adding the class block--invisible the whole Elements will not be clickable but all Elements behind it will be because of the pointer-events:none which is supported by all major browsers (no IE < 11).

Instead of using display you could store the element 'off-screen' until you needed it, then set its position to where you want it and transform it at the same time. This brings up a whole host of other design issues though, so ymmv. You probably wouldn't want to use display anyway, as you'd want the content to be accessible to screen readers, which for the most part try to obey rules for visibility - i.e., if it shouldn't be visible to the eye, it won't show up as content to the agent.

The simplest universal solution to the problem is: feel free to specify display:none in your CSS, however you will have change it to block (or whatever else) using JavaScript, and then you'll also have to add a class to your element in question that actually does the transition with setTimeout(). That's all.

You can do this with transition events, so what you so is, you build 2 css classes for the transition, one holding the animation other, holding the display none state. and you switch them after the animation is ended? In my case i can display the divs again if i press a btn, and remove both classes.

Try the snipped below...

$(document).ready(function() {
//assign transition event
$("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) {
//we check if this is the same animation we want
if (event.originalEvent.animationName == "col_hide_anim") {
//after the animation we assign this new class that basically hides the elements.
$(this).addClass("animation-helper-display-none");
}
});
$("button").click(function(event) {
$("table tr .hide-col").toggleClass(function() {
//we switch the animation class in a toggle fashion...
//and we know in that after the animation end, there is will the animation-helper-display-none extra class, that we nee to remove, when we want to show the elements again, depending on the toggle state, so we create a relation between them.
if ($(this).is(".animation-helper-display-none")) {
//im toggleing and there is already the above classe, then what we want it to show the elements , so we remove both classes...
return "visibility_switch_off animation-helper-display-none";
} else {
//here we just want to hide the elements, so we just add the animation class, the other will be added later be the animationend event...
return "visibility_switch_off";
}
});
});
});

You can get this to work the natural way you expected - using display - but you have to throttle the browser to get it to work, using either JS or as others have suggested a fancy trick with one tag inside another. I don't care for the inner tag as it further complicates CSS and dimensions, so here's the JS solution:

The key is throttling the display property. By removing the hidden class then waiting 50ms, then starting the transition via the added class, we get it to appear and then expand like we wanted, instead of it just blipping onto the screen without any animation. Similar occurs going the other way, except we wait till the animation is over before applying hidden.

Note: I'm abusing .animate(maxWidth) here to avoid setTimeout race conditions. setTimeout is quick to introduce hidden bugs when you or someone else picks up code unaware of it. .animate() can easily be killed with .stop(). I'm just using it to put a 50ms or 2000ms delay on the standard fx queue where it's easy to find/resolve by other coders building on top of this.

This skeleton helper will allow you to easily mimic jQuery show/hide but with in/out CSS3 transition animations.

It uses class toggles so you can use any css methods you want on elements besides display:none|block|table|inline etc as well as other alternate uses that can be thought up.

Its main design purpose is for element toggle states, it supports a revert state where hiding the object allows you to run your keyframe in reverse or play an alternate animation for hiding the element.

Most of the markup for the concept I am working on is CSS, there is very little javascript actually used.

Of course you could just use jQuery .fadeIn() and .fadeOut() functions, but the advantage of setting classes instead is in case you want to transition to a display value other than block (as is the default with .fadeIn() and .fadeOut()).

Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).