J Logo

Transitions on the CSS display property

I’m currently designing a CSS ‘mega dropdown’ menu — basically a regular CSS-only dropdown menu, but one that contains different types of content. At the moment, it appears that CSS 3 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). Is there 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 use 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.

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

You need to display: none otherwise you’ll be stumbling into the hidden object outside the trigger and it’ll be showing accidentally. I’m just saying 🙂

38 Answers 38

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

Читайте также:  Javascript регулярные выражения группы захвата

(Don’t forget the vendor prefixes to the transition property.)

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

This is nice but the problem is that «visibility hidden» elements still occupy space while «display none» does not.

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?

@GeorgeMillo if you set only the opacity, the element is actually still on the page rendering (you can’t click thought for example).

This should not be marked as the correct answer. It does not deal with the display property and as Rui said, the element still takes up space making it impractical for many situations.

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

I accomplished the effect by positioning both 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:

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:

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?

I implemented this, then it didn’t work, then I realised that what your saying is this won’t work. This answer assumes were not all just speed reading the important bits. 🙂

At the time of this post all major browsers disable CSS transitions if you try to change the display property, but CSS animations still work fine so we can use them as a workaround.

Example Code (you can apply it to your menu accordingly) Demo:

Add the following CSS to your stylesheet:

@-webkit-keyframes fadeIn < from < opacity: 0; >to < opacity: 1; >> @keyframes fadeIn < from < opacity: 0; >to < opacity: 1; >> 

Then apply the fadeIn animation to the child on parent hover (and of course set display: block ):

Update 2019 — Method that also supports fading out:

(Some JavaScript code is required)

// We need to keep track of faded in elements so we can apply fade out later in CSS document.addEventListener('animationstart', function (e) < if (e.animationName === 'fade-in') < e.target.classList.add('did-fade-in'); >>); document.addEventListener('animationend', function (e) < if (e.animationName === 'fade-out') < e.target.classList.remove('did-fade-in'); >>);
div < border: 5px solid; padding: 10px; >div:hover < border-color: red; >.parent .child < display: none; >.parent:hover .child < display: block; animation: fade-in 1s; >.parent:not(:hover) .child.did-fade-in < display: block; animation: fade-out 1s; >@keyframes fade-in < from < opacity: 0; >to < opacity: 1; >> @keyframes fade-out < from < opacity: 1; >to < opacity: 0; >>

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.

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.

Yeah, «change» — I’m not sure why I said «use» there. My point is you can’t transition or animate display , but that doesn’t prevent all other properties from animating either so long as you’re not transitioning to none.

This works perfectly for mouse-over dropdown menus where the height isn’t a problem. My dropdown simply fades in on hover of the parent nav item, and fades out when moused-out.

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

  1. When visible class is added, both height and opacity start animation without delay (0 ms), though height takes 0 ms to complete animation (equivalent of display: block ) and opacity takes 600 ms.
  2. When visible class is removed, opacity starts animation (0 ms delay, 400 ms duration), and height waits 400 ms and only then instantly (0 ms) restores initial value (equivalent of display: none in the animation callback).

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

For more examples please refer to this article.

It only works with height:100% which can destroy the layout in some cases. Great solution, if that’s not a problem. One of the few bidirectional working ones.

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 invisibility, it’s its own element rendering mode that means no rendering at all!).

Источник

How do you transition between display:none and display:block?

I’ve read elsewhere that modern browsers will disregard any animation or transition specifications if display: changes. Is this still the case? How can I overcome this and delay the appearance of the nav items until the overlay fully expands?

It appears to be working here: https://codepen.io/KingKabir/pen/QyPwgG but I’m not sure how they are accomplishing it?

I’ve tried using visibility: and opacity: but they don’t completely hide the 4 nav elements in the non-overlay state, thus messing up my name in the right side of the nav menu in the non-overlay state.

   
 .nav_container < display: grid; grid-template-columns: 1fr 1fr 1fr 1fr !important; grid-template-rows: auto; column-gap: 16px; grid-template-areas: "nav-far-left nav-left nav-right nav-far-right"; >.nav_container.open < max-height: 100%; height: 200%; background-color: #000000; display: grid; grid-template-rows: auto auto auto auto auto; grid-template-areas: "nav-far-left nav-left nav-right nav-far-right" "second second second second" "third third third third" "fourth fourth fourth fourth" "fifth fifth fifth fifth"; transition: all 0.4s cubic-bezier(0.455, 0.03, 0.515, 0.955); >.icon_personal_container,.blanks < display: none; >.nav_tab < display: block; height: 0; width: 0; visibility: hidden; opacity: 0; >.nav_tab.open < display: block; height: auto; font-size: 32px; font-weight: 500; padding-top: 64px; visibility: visible; opacity: 1; transition: visibility 0s linear; >#nav_tab_about.open < grid-area: second; transition-delay: .10s; width: auto; >#nav_tab_work.open < grid-area: third; transition-delay: .15s; width: auto; >#nav_tab_skills.open < grid-area: fourth; transition-delay: .2s; width: auto; >#nav_tab_contact.open < grid-area: fifth; transition-delay: .25s; width: auto; >#nav_text < grid-area: 1 / nav-right / 1 / nav-far-right; >

I expect the nav elements of class «nav_tab» to appear a few 10ths of a second after the nav_container has time to expand fully.

The current result is that the nav elements of class «nav_tab» appear immediately, before the nav_container has time to expand fully.

Источник

transition-delay

The transition-delay CSS property specifies the duration to wait before starting a property’s transition effect when its value changes.

Try it

The delay may be zero, positive, or negative:

  • A value of 0s (or 0ms ) will begin the transition effect immediately.
  • A positive value will delay the start of the transition effect for the given length of time.
  • A negative value will begin the transition effect immediately, and partway through the effect. In other words, the effect will be animated as if it had already been running for the given length of time.

You may specify multiple delays, which is useful when transitioning multiple properties. Each delay will be applied to the corresponding property as specified by the transition-property property, which acts as a master list. If there are fewer delays specified than in the master list, the list of delay values will be repeated until there are enough. If there are more delays, the list of delay values will be truncated to match the number of properties. In both cases, the CSS declaration remains valid.

Syntax

/* values */ transition-delay: 3s; transition-delay: 2s, 4ms; /* Global values */ transition-delay: inherit; transition-delay: initial; transition-delay: revert; transition-delay: revert-layer; transition-delay: unset; 

Values

Denotes the amount of time to wait between a property’s value changing and the start of the transition effect.

Formal definition

Источник

Оцените статью