Wulfen
Wulfen

Reputation: 33

Transition and Javascript

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

Answers (2)

Jack
Jack

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

Jason
Jason

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

Related Questions