skip to Main Content

Basically, I have two drop down buttons in a nav bar. Currently, when I hover the left button, the right button moves instantly to the right to let space for the drop down to appear. What I want is to let it slides smoothly to the right, not instantaneously.

I tried to apply "transition: 1s" but it requires a start and end value, and since the width property don’t change, the only thing changing is the display property (that hides the menu). How should I do it? I don’t want to use transform property… Have a nice day 🙂

        nav {
            display: flex;
            gap: 20px;
        }

        .nav_item>button {
            border: none;
        }

        .dropdown_item {
            text-decoration: none;
            color: black;
        }

        .dropdown_content {
            display: flex;
            flex-direction: column;
        }

        .hidden {
            display: none;
        }

        .nav_item:hover .hidden {
            display: block;
        }
        
<nav>
    <div class="nav_item">
        <button>File</button>
        <div class="hidden">
            <div class="dropdown_content">
                <a href="#" class="dropdown_item">Save map</a>
                <a href="#" class="dropdown_item">Load new map</a>
                <a href="#" class="dropdown_item">Another</a>
            </div>
        </div>
    </div>
    <div class="nav_item">
        <button>File</button>
        <div class="hidden">
            <div class="dropdown_content">
                <a href="#" class="dropdown_item">Save map</a>
                <a href="#" class="dropdown_item">Load new map</a>
                <a href="#" class="dropdown_item">Another</a>
            </div>
        </div>
    </div>
</nav>

2

Answers


  1. const firstNavItem = document.querySelector('.nav_item:nth-child(1)');
    const secondNavItem = document.querySelector('.nav_item:nth-child(2)');
    
    firstNavItem.addEventListener('mouseenter', () => {
      secondNavItem.classList.remove('shift');
    });
    
    firstNavItem.addEventListener('mouseleave', () => {
      secondNavItem.classList.add('shift');
    });
    nav {
      display: flex;
      gap: 20px;
    }
    
    .nav_item>button {
      border: none;
    }
    
    .dropdown_item {
      text-decoration: none;
      color: black;
    }
    
    .dropdown_content {
      display: flex;
      flex-direction: column;
    }
    
    .hidden {
      visibility: hidden;
    }
    
    .nav_item:hover .hidden {
      visibility: visible;
    }
    
    /* Add a negative left margin to the second nav item when the "shift" class is applied */
    .nav_item:nth-child(2).shift {
      margin-left: -120px; /* set the margin to be the width of the dropdown menu */
      transition: margin-left 1s; /* add the transition property */
    }
    <nav>
      <div class="nav_item">
        <button>File</button>
        <div class="hidden">
          <div class="dropdown_content">
            <a href="#" class="dropdown_item">Save map</a>
            <a href="#" class="dropdown_item">Load new map</a>
            <a href="#" class="dropdown_item">Another</a>
          </div>
        </div>
      </div>
      <div class="nav_item">
        <button>File</button>
        <div class="hidden">
          <div class="dropdown_content">
            <a href="#" class="dropdown_item">Save map</a>
            <a href="#" class="dropdown_item">Load new map</a>
            <a href="#" class="dropdown_item">Another</a>
          </div>
        </div>
      </div>
    </nav>
    Login or Signup to reply.
  2. It’s not advised to try and animate the display property, but that being said, there are some clever people out there and some hacks you can do:

            
            nav {
                display: flex;
                gap: 20px;
            }
    
            .nav_item>button {
                border: none;
            }
    
            .dropdown_item {
                text-decoration: none;
                color: black;
            }
    
            .dropdown_content {
                display: flex;
                flex-direction: column;
                width: 100px;
            }
    
            .hidden {
                animation: show .2s;
                display: none;
            }
    
            .nav_item:hover .hidden {
                display: block;
            }
    
            @keyframes show {
                from { width: 0; }
                to { width: 100px; }
            }
            
    <nav>
        <div class="nav_item">
            <button>File</button>
            <div class="hidden">
                <div class="dropdown_content">
                    <a href="#" class="dropdown_item">Save map</a>
                    <a href="#" class="dropdown_item">Load new map</a>
                    <a href="#" class="dropdown_item">Another</a>
                </div>
            </div>
        </div>
        <div class="nav_item">
            <button>File</button>
            <div class="hidden">
                <div class="dropdown_content">
                    <a href="#" class="dropdown_item">Save map</a>
                    <a href="#" class="dropdown_item">Load new map</a>
                    <a href="#" class="dropdown_item">Another</a>
                </div>
            </div>
        </div>
    </nav>

    The above was inspired by CSS Tricks post about animating display properties.

    I believe this achieves the desired effect from your initial question.

    That being said, I’d suggest taking a far simpler (and cleaner) route by simply adding position: absolute into the .dropdown_content class:

            
            nav {
                display: flex;
                gap: 20px;
            }
    
            .nav_item>button {
                border: none;
            }
    
            .dropdown_item {
                text-decoration: none;
                color: black;
            }
    
            .dropdown_content {
                display: flex;
                flex-direction: column;
                position: absolute;
            }
    
            .hidden {
                display: none;
            }
    
            .nav_item:hover .hidden {
                display: block;
            }
            
    <nav>
        <div class="nav_item">
            <button>File</button>
            <div class="hidden">
                <div class="dropdown_content">
                    <a href="#" class="dropdown_item">Save map</a>
                    <a href="#" class="dropdown_item">Load new map</a>
                    <a href="#" class="dropdown_item">Another</a>
                </div>
            </div>
        </div>
        <div class="nav_item">
            <button>File</button>
            <div class="hidden">
                <div class="dropdown_content">
                    <a href="#" class="dropdown_item">Save map</a>
                    <a href="#" class="dropdown_item">Load new map</a>
                    <a href="#" class="dropdown_item">Another</a>
                </div>
            </div>
        </div>
    </nav>

    This removes all width dependancy from the equation and makes the user experience more predictable.

    I hope this helps.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search