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

I've came across this issue multiple times and now simply went with:

.block {
  opacity: 1;
  transition: opacity 250ms ease;
}

.block--invisible {
  pointer-events: none;
  opacity: 0;
}

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).

查看更多
怪性笑人.
3楼-- · 2018-12-31 00:29

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.

查看更多
高级女魔头
4楼-- · 2018-12-31 00:31

You can concatenate two transitions or more, and visibility is what comes handy this time.

div {
  border: 1px solid #eee;
}
div > ul {
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity 0.5s linear;
}
div:hover > ul {
  visibility: visible;
  opacity: 1;
}
<div>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>
</div>

(Don't forget the vendor prefixes to the transition property)

More details are in this article

查看更多
残风、尘缘若梦
5楼-- · 2018-12-31 00:31

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";
      }

    });

  });

});
table th {
  background-color: grey;
}

table td {
  background-color: white;
  padding:5px;
}

.animation-helper-display-none {
  display: none;
}

table tr .visibility_switch_off {
  animation-fill-mode: forwards;
  animation-name: col_hide_anim;
  animation-duration: 1s;
}

@-webkit-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@-moz-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@-o-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@keyframes col_hide_anim {
  0%   {opacity: 1;}
  100% {opacity: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <theader>
    <tr>
      <th>Name</th>
      <th class='hide-col'>Age</th>
      <th>Country</th>
    </tr>
  </theader>
  <tbody>
    <tr>
      <td>Name</td>
      <td class='hide-col'>Age</td>
      <td>Country</td>
    </tr>
  </tbody>
</table>

<button>Switch - Hide Age column with fadeout animation and display none after</button>

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

You need to hide the element by other means in order to get this to work.

I accomplished the effect by positioning both <div>s absolutely and setting the hidden one to opacity: 0.

If you even toggle the display property from none to block, Your transition on other elements will not occur.

To work around this, always allow the element to be display: block, but hide the element by adjusting any of these means:

  1. Set the height to 0.
  2. Set the opacity to 0.
  3. Position the element outside of the frame of another element that has overflow: hidden.

There are likely more solutions, but you cannot perform a transition if you toggle the element to display: none. For example, you may attempt to try something like this:

div {
    display: none;
    transition: opacity 1s ease-out;
    opacity: 0; 
}
div.active {
    opacity: 1;
    display: block;
}

But that will not work. From my experience, I have found this to do nothing.

Because of this, you will always need to keep the element display: block - but you could get around it by doing something like this:

div {
    transition: opacity 1s ease-out;
    opacity: 0; 
    height: 0;
    overflow: hidden;
}
div.active {
    opacity: 1;
    height: auto;
}
查看更多
看风景的人
7楼-- · 2018-12-31 00:33

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!),

查看更多
登录 后发表回答