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:19

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.

I.e.:

<style>
#el {
    display: none;
    opacity: 0;
}
#el.auto-fade-in {
    opacity: 1;
    transition: all 1s ease-out; /* future, future, please come sooner! */
    -webkit-transition: all 1s ease-out;
    -moz-transition: all 1s ease-out;
    -o-transition: all 1s ease-out;
}
</style>

<div id=el>Well, well, well</div>

<script>
var el = document.getElementById('el');
el.style.display = 'block';
setTimeout(function () { el.className = 'auto-fade-in' }, 0);
</script>

Tested in the latest sane browsers. Obviously shouldn't work in IE9 or earlier.

查看更多
与风俱净
3楼-- · 2018-12-31 00:20

My neat JavaScript trick is to separate the entire scenario into two different functions!

To prepare things, one global variable is declared and one event handler is defined:

  var tTimeout;
  element.addEventListener("transitionend", afterTransition, true);//firefox
  element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome

Then, when hiding element, I use something like this:

function hide(){
  element.style.opacity = 0;
}

function afterTransition(){
  element.style.display = 'none';
}

For reappearing the element, I am doing something like this:

function show(){
  element.style.display = 'block';
  tTimeout = setTimeout(timeoutShow, 100);
}

function timeoutShow(){
  element.style.opacity = 1;
}

It works, so far!

查看更多
浅入江南
4楼-- · 2018-12-31 00:21

I know this is a very old question but for people who are looking at this thread, you can add a custom animation to the block property now.

@keyframes showNav {
  from {opacity: 0;}
  to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
  display: block;
  animation: showNav 250ms ease-in-out both;
}

Demo

In this demo the sub-menu changes from display:none to display:block and still manages to fade.

查看更多
孤独寂梦人
5楼-- · 2018-12-31 00:21

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:

HTML

<nav>
  <input type="checkbox" />
  <ul>
    <li>Link 1</li>
    <li>Link 1</li>
    <li>Link 1</li>
    <li>Link 1</li>
  </ul>
</nav>

CSS

nav input + ul li { // notice I set max-height on li, not ul
   max-height: 0;
}

nav input:checked + ul li {
   max-height: 3rem; // a little bigger to allow for text-wrapping - but not outrageous
}

See an example here: http://codepen.io/mindfullsilence/pen/DtzjE

查看更多
情到深处是孤独
6楼-- · 2018-12-31 00:22

display is not one of the properties that transition works upon.

See https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties for the list of CSS properties that can have transitions applied to them. See https://drafts.csswg.org/css-values-4/#combining-values for how they are interpolated.

Up to CSS3 was listed in https://www.w3.org/TR/2017/WD-css-transitions-1-20171130/#animatable-css (just close the warning popup)

查看更多
看淡一切
7楼-- · 2018-12-31 00:22

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:

.myclass > div { 
                   transition:visibility 1s, opacity 1s; 
                   visibility:hidden;  opacity:0
               }
.myclass:hover > div 
               {   visibility:visible; opacity:1 }

The run time specified for both transitions should usually be identical (although a slightly longer time for visibility is not a problem). For a running version, see my blog http://www.taccgl.org/blog/css-transition-visibility.html#visibility-opacity.

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.

查看更多
登录 后发表回答