Transitions on the display: property

2018-12-31 00:08发布

I'm currently designing a kind of CSS 'mega dropdown' menu - basically a normal CSS-only dropdown menu, but one that contains different types of content.

At the moment, it appears that CSS3 Transitions don't apply to the 'display' property, i.e. you can't do any sort of transition from display: none to display: block (or any combination).

Can anyone think of a way for the second-tier menu from the above example to 'fade in' when someone hovers over one of the top level menu items?

I'm aware that you can use transitions on the visibility: property, but I can't think of a way to utilise that effectively.

I've also tried using height but that just failed miserably.

I'm also aware that it's trivial to achieve this using JavaScript, but I wanted to challenge myself to use just CSS and I think I'm coming up a little short.

All and any suggestions most welcome.

29条回答
与君花间醉酒
2楼-- · 2018-12-31 00:40

I finally found a solution for me, by combining opacity with position absolute (not to occupy space when hidden).

.toggle {
  opacity: 0;
  position: absolute;
  transition: opacity 0.8s;
}

.parent:hover .toggle {
  opacity: 1;
  position: static;
}
查看更多
像晚风撩人
3楼-- · 2018-12-31 00:40

I feel almost bad answering to a question with that many answers, but this solution has excellent compatibility and I haven't seen it yet:

.hidden-element {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity .5s ease-out;
}

.hidden-element.visible {
  position: static;
  z-index: auto;
  pointer-events: auto;
  visibility: visible;
  opacity: 1;
}

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.

查看更多
长期被迫恋爱
4楼-- · 2018-12-31 00:41

Instead of callbacks, which don't exist in CSS, we can use transition-delay property.

#selector {
    overflow: hidden; // hide the element content, while height = 0
    height: 0; opacity: 0;
    transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
    height: 100%; opacity: 1;
    transition: height 0ms 0ms, opacity 600ms 0ms;
}

So, what's going on here?

  1. When visible class is added, both height and opacity start animation without delay (0ms), though height takes 0ms to complete animation (equivalent of display: block) and opacity takes 600ms.

  2. When visible class is removed, opacity starts animation (0ms delay, 400ms duration), and height waits 400ms and only then instantly (0ms) restores initial value (equivalent of display: none in the animation callback).

Note, this approach is better, than ones using visibility. In such case the element still occupies the space on the page, and it's not always suitable.

For more examples please refer this article.

查看更多
无色无味的生活
5楼-- · 2018-12-31 00:41

Taking from a few of these answers and some suggestions elsewhere, the following works great for hover menus (I'm using this with bootstrap 3, specifically):

nav .dropdown-menu {
    display: block;
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition: max-height 500ms, opacity 300ms;
    -webkit-transition: max-height 500ms, opacity 300ms;
}
nav .dropdown:hover .dropdown-menu {
    max-height: 500px;
    opacity: 1;
    transition: max-height 0, opacity 300ms;
    -webkit-transition: max-height 0, opacity 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.

查看更多
若你有天会懂
6楼-- · 2018-12-31 00:45

I think SalmanPK has the closest answer, it does fade an item in or out, with the following CSS animations. However the display property does not animate smoothly, only the opacity.

@-webkit-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

@-webkit-keyframes fadeOut {
    from { opacity: 1; }
      to { opacity: 0; }
}

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.

jsFiddle example

CSS

@-webkit-keyframes pushDown {
  0% {
    height: 10em;
  }
  25% {
    height: 7.5em;
  }
  50% {
    height: 5em;
  }
  75% {
    height: 2.5em;
  }
  100% {
    height: 0em;
  }
}

.push-down {
    -webkit-animation: pushDown 2s forwards linear;
}

JavaScript

var element = document.getElementById("element");

// push item down
element.className = element.className + " push-down";
查看更多
登录 后发表回答