Reputation: 33
Apologies in advance, I am completely new to transitions.
I am working with CSS and JavaScript to attempt a menu that slides down smoothly on click, and returns just as smoothly with another click.
I tried to mimic an example animation as shown in here: https://codepen.io/shshaw/pen/gsFch
My relevant code is as follows:
HTML
<div class="sort">
<div class="sort-options">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</div>
CSS
.sort-options {
margin: 20px;
display: none;
flex-direction: column;
align-items: flex-start;
font-size: 20px;
width: 100%;
transition: display 3s ease-out;
}
JS
const sortDiv = document.querySelector('.sort')
sortDiv.addEventListener('click', function() {
const sortOptions = document.querySelector('.sort-options');
if (sortOptions.style.display === 'none') {
sortOptions.style.display = 'flex';
} else {
sortOptions.style.display = 'none';
}
});
The click does hide and show the element, but no animation is given. I tried to achieve the effect using only CSS, but I have found the same result, in which it does hide and show, but no smooth sliding down. This makes me think I am not doing something right with CSS.
CSS only attempt:
.sort:hover .sort-options {
display: flex;
}
.sort-options {
visibility: hidden;
margin: 20px;
display: none;
flex-direction: column;
align-items: flex-start;
font-size: 20px;
width: 100%;
transition: all 3s ease-in-out;
}
My full code is here if you want to review it: https://wulfenn.github.io/todolist
I did some browsing around stackoverflow and it seems that display is not supported as a transition effect, but I am not certain how to achieve the effect using visibility while not occupying the space if the div is not visible.
Help appreciated!
Upvotes: 0
Views: 158
Reputation: 1999
This is because your using display
to animate, which is not animated. You're looking for opacity
and pointer-events
which can give a similar result.
Below is an example
.sort {
width: 100px;
text-align: center;
}
.sort-heading {
position: relative;
z-index: 2;
background-color: white;
}
.sort:hover .sort-options {
opacity: 1;
transform: translateY(0px);
pointer-events: all;
}
.sort-options {
display: flex;
width: 100%;
flex-direction: column;
align-items: flex-start;
margin: 20px;
font-size: 20px;
transition: all 3s ease-in-out;
transform: translateY(-50px);
opacity: 0;
pointer-events: none;
}
<div class="sort">
<div class="sort-heading">Sort</div>
<div class="sort-options">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</div>
First I removed visibility: hidden
which was not necessary. I also made it always have display: flex
and then simply remove the opacity
to have it fade in. I also used pointer-events
so that the mouse won't interact with it while it's hidden. I used transform: translateY(-50px)
so it would go down some. I also had to add a heading that could be hovered on to make the menu appear (sort-heading
). Its also used to hide the options as they come down.
Edit
To not take up space, just add position: absolute
to .sort-options
.
If you want to control it with just JS, change your CSS line to .sort:hover .sort-options {
to .sort.active .sort-options {
Now you can easily open and close the dropdown with
//Open
document.querySelector('.sort').classList.add('active');
//Close
document.querySelector('.sort').classList.remove('active');
If you still want the hover event you can either control that with JS or CSS
JS
var sortEle = document.querySelector('.sort');
sortEle.onmouseenter = function() {
//Open
sortEle.classList.add('active');
}
sortEle.onmouseleave = function() {
//Close
sortEle.classList.remove('active');
}
CSS
Make .sort.active .sort-options {
.sort.active .sort-options, .sort:hover .sort-options {
Upvotes: 1
Reputation: 367
The reason display as a transition
is not working, is because there are no values to animate(transition) to/from. The display attribute is more like on/off.
Here is a simple example...
#container {
position: relative;
height: 2rem;
width: 300px;
background-color: blue;
margin: auto;
}
.menu {
position: absolute;
visibility: hidden;
display: flex;
top: 2rem;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: grey;
height: 0rem;
width: 100%;
overflow: hidden;
transition: height 1s ease-in-out, visibility 1s ease-in-out;
}
#container:hover .menu{
visibility: visible;
height: 8rem;
}
<div id='container'>
<div class='menu'>
<p>item 1</p>
<p>item 2</p>
<p>item 3</p>
</div>
</div>
Upvotes: 0