[css] CSS transition with visibility not working

In the fiddle below, I've a transition on visibility and opacity separately. The latter works but the former doesn't. Moreover, in case of visibility, the transition time is interpreted as delay on hover out. Happens in both Chrome & Firefox. Is this a bug?

http://jsfiddle.net/0r218mdo/3/

Case 1:

#inner{
    visibility:hidden;
    transition:visibility 1000ms;
}
#outer:hover #inner{
    visibility:visible;
}

Case 2:

#inner1{
    opacity:0;
    transition:opacity 1000ms;
}
#outer1:hover #inner1{
    opacity:1;
}

This question is related to css css-transitions

The answer is


This is not a bug- you can only transition on ordinal/calculable properties (an easy way of thinking of this is any property with a numeric start and end number value..though there are a few exceptions).

This is because transitions work by calculating keyframes between two values, and producing an animation by extrapolating intermediate amounts.

visibility in this case is a binary setting (visible/hidden), so once the transition duration elapses, the property simply switches state, you see this as a delay- but it can actually be seen as the final keyframe of the transition animation, with the intermediary keyframes not having been calculated (what constitutes the values between hidden/visible? Opacity? Dimension? As it is not explicit, they are not calculated).

opacity is a value setting (0-1), so keyframes can be calculated across the duration provided.

A list of transitionable (animatable) properties can be found here


Visibility is an animatable property according to the spec, but transitions on visibility do not work gradually, as one might expect. Instead transitions on visibility delay hiding an element. On the other hand making an element visible works immediately. This is as it is defined by the spec (in the case of the default timing function) and as it is implemented in the browsers.

This also is a useful behavior, since in fact one can imagine various visual effects to hide an element. Fading out an element is just one kind of visual effect that is specified using opacity. Other visual effects might move away the element using e.g. the transform property, also see http://taccgl.org/blog/css-transition-visibility.html

It is often useful to combine the opacity transition with a visibility transition! Although opacity appears to do the right thing, fully transparent elements (with opacity:0) still receive mouse events. So e.g. links on an element that was faded out with an opacity transition alone, still respond to clicks (although not visible) and links behind the faded element do not work (although being visible through the faded element). See http://taccgl.org/blog/css-transition-opacity-for-fade-effects.html.

This strange behavior can be avoided by just using both transitions, the transition on visibility and the transition on opacity. Thereby the visibility property is used to disable mouse events for the element while opacity is used for the visual effect. However care must be taken not to hide the element while the visual effect is playing, which would otherwise not be visible. Here the special semantics of the visibility transition becomes handy. When hiding an element the element stays visible while playing the visual effect and is hidden afterwards. On the other hand when revealing an element, the visibility transition makes the element visible immediately, i.e. before playing the visual effect.


Visibility is animatable. Check this blog post about it: http://www.greywyvern.com/?post=337

You can see it here too: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties

Let's say you have a menu that you want to fade-in and fade-out on mouse hover. If you use opacity:0 only, your transparent menu will still be there and it will animate when you hover the invisible area. But if you add visibility:hidden, you can eliminate this problem:

_x000D_
_x000D_
div {_x000D_
    width:100px;_x000D_
    height:20px;_x000D_
}_x000D_
.menu {_x000D_
    visibility:hidden;_x000D_
    opacity:0;_x000D_
    transition:visibility 0.3s linear,opacity 0.3s linear;_x000D_
    _x000D_
    background:#eee;_x000D_
    width:100px;_x000D_
    margin:0;_x000D_
    padding:5px;_x000D_
    list-style:none;_x000D_
}_x000D_
div:hover > .menu {_x000D_
    visibility:visible;_x000D_
    opacity:1;_x000D_
}
_x000D_
<div>_x000D_
  <a href="#">Open Menu</a>_x000D_
  <ul class="menu">_x000D_
    <li><a href="#">Item</a></li>_x000D_
    <li><a href="#">Item</a></li>_x000D_
    <li><a href="#">Item</a></li>_x000D_
  </ul>_x000D_
</div>
_x000D_
_x000D_
_x000D_