I know this question has probably been asked million times here in SO, but Ive tried most of the solution, I just dont know why it dont work for me.
So I have a dropdown with display
initially targeted to none
. When I click on it, it shows nice transition. (So far so good). But when I click on it again to go hide the dropdown, it hides immediately, but I dont want that. I want to hide with similar transition that was assigned to show. Here is my code for CSS:
.dropdown-menu {
padding: 0 0;
display: none;
-webkit-animation: slide-down .3s ease-out;
-moz-animation: slide-down .3s ease-out;
}
.table-dropdown-open {
display: block;
-webkit-animation: slide-down .3s ease-out;
-moz-animation: slide-down .3s ease-out;
}
@-webkit-keyframes slide-down {
0% {
opacity: 0;
-webkit-transform: translateY(-10%);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
}
}
@-moz-keyframes slide-down {
0% {
opacity: 0;
-moz-transform: translateY(-10%);
}
100% {
opacity: 1;
-moz-transform: translateY(0);
}
}
This is not a dupliacte because Im trying to give transition from block
to
none
. Not from none
to block
When we want to use transition for display:none to display:block, transition properties do not work. The reason for this is, display:none property is used for removing block and display:block property is used for displaying block.
getElementById("element"). style. display = "none"; To show an element, set the style display property to “block”.
display: none doesn't have a literal opposite like visibility:hidden does. The visibility property decides whether an element is visible or not. It therefore has two states ( visible and hidden ), which are opposite to each other.
display
your element at all times and only transition
any animatable
property. In your case, opacity
looks like a good candidate, though playing with transform
might also give you the desired result. Simple example:
any {
transform: scale(0);
transition: transform .4s cubic-bezier(.5,0,.3,1);
}
any.animated {
transform: scale(1);
}
In effect, opacity
and transform
should be the only two properties you should animate, as they don't require DOM
repaint on anything other than the animated element, thus not hitting browser performance, even when you're animating a considerable amount of elements simultaneously.
Please note that, even if not painted, your elements are, in effect, in the place where they would be when not transform
ed at all. So you might want to give them pointer-events:none
when they are in the "invisible" state and pointer-events:all
when they are in "visible" state, so they don't catch any pointer events while not visible.
Considering your example, I've given you two animation examples (with keyframes and without). Remember you need to prefix your code
. For full browser compatibility, use > 0%
in settings (the small box at the bottom).
setTimeout(function(){
var dm = document.querySelector('.dropdown-menu');
dm.classList.remove('hide-menu');
}, 300);
/* simple animation example, on parent. No keyframes. */
.dropdown-menu.hide-menu {
opacity: 0;
}
.dropdown-menu {
opacity: 1;
transition: opacity .2s cubic-bezier(.4,0,.2,1);
position: relative;
animation: delay-overflow .3s;
animation-fill-mode: forwards;
animation-iteration-count: 1;
}
.dropdown-menu:hover {
animation: none;
cursor: pointer;
}
/* animation example with keyframes, on child */
.dropdown-menu ul {
position: absolute;
margin-top: 0;
padding-top: 1rem;
top: 100%;
opacity: 0;
transform: translateY(-10%);
animation: slide-up .3s;
animation-fill-mode: forwards;
animation-iteration-count: 1;
}
.drowdown-menu.hide-menu ul {
animation-duration: 0s;
}
.dropdown-menu:hover ul {
animation: slide-down .3s;
animation-fill-mode: forwards;
}
@keyframes slide-down {
from {
opacity: 0;
transform: translateY(-10%);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slide-up {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(-10%);
}
}
@keyframes delay-overflow {
0% {
overflow: visible;
}
99% {
overflow: visible;
}
100% {
overflow: hidden;
}
}
<div class="dropdown-menu hide-menu">
<span>Menu</span>
<ul>
<li>A menu item</li>
<li>Another menu item</li>
<li>...</li>
<li>And so on...</li>
</ul>
</div>
Note: A very handy trick with animation
property is that it allows you to delay applying any property, even non-animatable ones from applying for the desired amount of time. I'm using this trick to delay overflow:hidden
applying on the parent (and overflow
is not animatable) so the animation of the child - which happens outside the bounds of the parent - is visible until the end. After it finishes, the overflow:hidden
applies and it no longer catches mouse events outside the menu opener.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With