-1

So I'm making a menu interaction on click, this is my code snippet if you want to have a look.

let btn = document.querySelector('.trigger');
let icons = document.querySelector('.icons');
let labels = document.querySelector('.labels');
btn.onclick = function() {
  icons.classList.toggle('active');
  labels.classList.toggle('active');
}
body {
  background: #222;
}

.trigger {
  cursor: pointer;
}

nav {
  position: absolute;
  top: 30px;
  right: 30px;
  color: #222;
}

nav ul.icons {
  background: #fff;
  width: 60px;
  height: 60px;
  overflow: hidden;
  border-radius: 60px;
  transition: 1s ease;
}

nav ul.icons:hover {
  height: 100%;
}

nav ul li {
  list-style: none;
}
<html lang="en">

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
</head>

<body>
  <nav>
    <ul class="icons">
      <li class="trigger">
        <i class="fas fa-bars"></i>
      </li>
      <li><i class="fas fa-home"></i></li>
      <li><i class="fas fa-users"></i></li>
      <li><i class="fas fa-concierge-bell"></i></li>
      <li><i class="fas fa-pen"></i></li>
      <li><i class="fas fa-phone-alt"></i></li>
    </ul>
  </nav>
</body>

</html>

The issue that I have is that the transition property doesn't work well with height in CSS. Is there a problem that I didn't noticed, and is there a quick fix to it?

  • 2
    First of all you don't have any `active` class in your css. So what are you trying to achieve?? – Kunal Tanwar Aug 22 '21 at 13:01
  • 1
    What @KunalTanwar said. Also, when you create the `.active` class, you'll need to set an exact `height` value for the transition to work. – Steve Aug 22 '21 at 13:05
  • @KunalTanwar the active class will appear when the menu button is clicked, it's in the javascript by the way. –  Aug 22 '21 at 13:09

3 Answers3

0

The CSS transition of the "height" property works only if both values ​​(starting and ending) are specified.

You can get around this by using "max-height" instead of "height". This way you can safely exceed the exact height that the element should have at the end of the transition.

let btn = document.querySelector('.trigger');
let icons = document.querySelector('.icons');
let labels = document.querySelector('.labels');
btn.onclick = function() {
  icons.classList.toggle('active');
  labels.classList.toggle('active');
}
body {
  background: #222;
}

.trigger {
  cursor: pointer;
}

nav {
  position: absolute;
  top: 30px;
  right: 30px;
  color: #222;
}

nav ul.icons {
  background: #fff;
  width: 60px;
  max-height: 60px;
  overflow: hidden;
  border-radius: 60px;
  transition: max-height 1s ease;
}

nav ul.icons:hover {
  max-height: 120px;
}

nav ul li {
  list-style: none;
}
<html lang="en">

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
</head>

<body>
  <nav>
    <ul class="icons">
      <li class="trigger">
        <i class="fas fa-bars"></i>
      </li>
      <li><i class="fas fa-home"></i></li>
      <li><i class="fas fa-users"></i></li>
      <li><i class="fas fa-concierge-bell"></i></li>
      <li><i class="fas fa-pen"></i></li>
      <li><i class="fas fa-phone-alt"></i></li>
    </ul>
  </nav>
</body>

</html>

The only side effect could be too much delay in the return transition if you set a final value that is too high compared to what is needed.

CostyEffe
  • 1
  • 1
0

Just a very basic snippet of what you wanted to create on the first place.

[NOTE] : Transition is quite/bit cranky (not smooth). But it is what it is.

document.querySelector('.menu').addEventListener('click', (e) => {
  document.querySelector('ul.icons').classList.toggle('active');
});
* {
  margin: 0;
  padding: 0;
  outline: 0;
  box-sizing: border-box;
}

.navbar {
  position: relative;
  width: 100%;
  height: 100px;
  display: flex;
  padding: 0 4rem;
  align-items: center;
  justify-content: flex-end;
  background-color: #f7f8f9;
  border-bottom: 1px solid #c1c1c1;
}

.navbar .menu i {
  cursor: pointer;
  font-size: 2rem;
}

.navbar .icons {
  opacity: 0;
  list-style: none;
  position: absolute;
  top: calc(100% + 2px);
  right: 3rem;
  display: flex;
  flex-direction: column;
  transition: opacity 250ms ease;
}

.navbar .icons .icon {
  display: grid;
  padding: 1rem;
  flex-shrink: 0;
  min-width: 30px;
  min-height: 30px;
  border-radius: 50%;
  place-items: center;
  background-color: #f7f8f9;
  border: 1px solid #c1c1c1;
  transition: margin-top 250ms ease;
}

.navbar .icons .icon:not(:first-of-type) {
  margin-top: 1rem;
}

.navbar .icons .icon:nth-child(2) {
  margin-top: -62px;
}

.navbar .icons .icon:nth-child(3) {
  margin-top: -62px;
}

.navbar .icons .icon:nth-child(4) {
  margin-top: -62px;
}

.navbar .icons .icon:nth-child(5) {
  margin-top: -62px;
}

.navbar .icons.active {
  opacity: 1;
}

.navbar .icons.active .icon {
  margin-top: 1rem;
}

.navbar .icons.active .icon:nth-child(1) {
  margin-top: 0;
  transition-delay: 250ms;
}

.navbar .icons.active .icon:nth-child(2) {
  transition-delay: 250ms;
}

.navbar .icons.active .icon:nth-child(2) {
  transition-delay: 500ms;
}

.navbar .icons.active .icon:nth-child(3) {
  transition-delay: 750ms;
}

.navbar .icons.active .icon:nth-child(4) {
  transition-delay: 1s;
}

.navbar .icons.active .icon:nth-child(5) {
  transition-delay: 1.25s;
}

.bx {
  font-size: 1.75rem;
}
<link href='https://unpkg.com/boxicons@2.0.9/css/boxicons.min.css' rel='stylesheet'>

<nav class="navbar">
  <div class="menu" role="button">
    <i class='bx bx-menu'></i>
  </div>
  <ul class="icons">
    <li class="icon">
      <i class='bx bx-home-alt'></i>
    </li>
    <li class="icon">
      <i class='bx bx-user'></i>
    </li>
    <li class="icon">
      <i class='bx bx-bell'></i>
    </li>
    <li class="icon">
      <i class='bx bx-pen'></i>
    </li>
    <li class="icon">
      <i class='bx bx-phone'></i>
    </li>
  </ul>
</nav>

If anyone can make this transition a bit more smooth edit this answer.

Kunal Tanwar
  • 1,209
  • 1
  • 8
  • 23
0

So the problem is that you try to transition the height to 100% - but CSS can't handle that right away.

Fast but problematic solution:
You could set the height in the :hover to a fixed amount, e.g. 100px.
But if you want to have a new item in there or change the size of the items, you would have to adjust the height manually.

What I would do:
First I would restructure the HTML a bit and move the trigger out of the item list:

<nav>
    <button class="trigger">
        <i class="fas fa-bars"></i>
    </button>
    <ul class="icons fas-container">
        <li><i class="fas fa-home"></i></li>
        <li><i class="fas fa-users"></i></li>
        <li><i class="fas fa-concierge-bell"></i></li>
        <li><i class="fas fa-pen"></i></li>
        <li><i class="fas fa-phone-alt"></i></li>
    </ul>
</nav>

Then I would adjust the CSS of the .icons:
(remove the height, add a max-height and adjust the transition)

nav ul.icons {
    background: #fff;
    width: 60px;
    overflow: hidden;
    border-radius: 60px;

    max-height: 0;
    transition: max-height 0.2s ease-out;
}

In the end I would let JavaScript take care of getting the max-height right.
On hover:

let btn = document.querySelector('.trigger');
let icons = document.querySelector('.icons');
btn.onmouseover = function () {
    icons.style.maxHeight = icons.scrollHeight + "px";
}
btn.onmouseout = function () {
    icons.style.maxHeight = null;
}

Or on click (if you would rather do that):

let btn = document.querySelector('.trigger');
let icons = document.querySelector('.icons');

btn.onclick = function() {
    if (icons.style.maxHeight){
        icons.style.maxHeight = null;
    } else {
        icons.style.maxHeight = icons.scrollHeight + "px";
    }
}

Here are some (maybe) helpfull links:

Snippet:

let btn = document.querySelector('.trigger');
    let icons = document.querySelector('.icons');
    btn.onmouseover = function () {
        icons.style.maxHeight = icons.scrollHeight + "px";
    }
    btn.onmouseout = function () {
        icons.style.maxHeight = null;
    }
body {
        background: #222;
    }

    .trigger {
        cursor: pointer;
    }

    nav {
        position: absolute;
        top: 30px;
        right: 30px;
        color: #222;
    }

    nav ul.icons {
        background: #fff;
        width: 60px;
        overflow: hidden;
        border-radius: 60px;

        max-height: 0;
        transition: max-height 0.2s ease-out;
    }

    nav ul.icons:hover {
        height: 100%;
    }

    nav ul li {
        list-style: none;
    }
<html lang="en">

<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
</head>

<body>
<nav>
    <button class="trigger">
        <i class="fas fa-bars"></i>
    </button>
    <ul class="icons fas-container">
        <li><i class="fas fa-home"></i></li>
        <li><i class="fas fa-users"></i></li>
        <li><i class="fas fa-concierge-bell"></i></li>
        <li><i class="fas fa-pen"></i></li>
        <li><i class="fas fa-phone-alt"></i></li>
    </ul>
</nav>
</body>

</html>