Menu Underline effect 3

by davidxmartins

HTML

<header class="menu-big">

  <span class="logo">DAVID MARTINS</span>

  <div class="menu-container">
    <nav class="menu">
      <ul class="menu__list">
        <li><a href="#" class="menu__link active">Work</a></li>
        <li><a href="#" class="menu__link">Services</a></li>
        <li><a href="#" class="menu__link">Journal</a></li>
        <li><a href="#" class="menu__link">Info</a></li>
      </ul>
    </nav>
  </div>

</header>

CSS

/* 
  ====================
  Menu Big
  ====================
  */
  
  /* Container */
  
  header.menu-big {
    margin: 0 auto;
    width: 95%;
    max-width: 1200px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: ;
    height: auto;
    box-sizing: border-box;
    padding: 30px 0 10px 0;
    z-index: 9;
    border-bottom: 1px solid #ccc;
}


/* Logo */

.logo {
    font-family: "DMfont_bold", sans-serif;
    font-size: 1.5em;
    padding-left: 1.2vw;
}

/* menu */

.menu-container {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: row;
}

.menu__list {
    --color-underline: black;
    --underline-width: 0;
    --underline-offset-x: 0;
    position: relative;
    display: inline-flex;
    margin: 0;
    padding: 0;
    list-style: none;
}

.menu__list::before {
content: "";
display: block;
position: absolute;
top: calc(100% + 8px); /* Underline effect aligns with the bottom of the header */
height: 3px;
width: var(--underline-width);
transform: translateX(var(--underline-offset-x));
background-color: black;
transition: transform 0.5s, width 0.5s;
border-radius: /* Optional, if you want rounded corners */;
}

.menu__link {
    display: block;
    padding: 0.5rem 1.2vw;
    color: black;
    text-decoration: none;
    font-family: "DMfont_medium", sans-serif;
    font-size: 1em;
    text-transform: uppercase;
    cursor: pointer;
    letter-spacing: 0.1rem;
}

/* Active Link */
.menu__link.active {
    position: relative;
}

.menu__list::before {
    content: "";
    display: block;
    position: absolute;
    top: calc(100% + 8px); /* Underline effect aligns with the bottom of the header */
    height: 3px;
    width: var(--underline-width);
    transform: translateX(var(--underline-offset-x));
    background-color: black;
    transition: transform 0.5s, width 0.5s;
}

JavaScript

document.addEventListener("DOMContentLoaded", () => {
    const menu = document.querySelector(".menu__list");
    const links = document.querySelectorAll(".menu__link");
    const activeLink = document.querySelector(".menu__link.active");

    // Store the initial position and width of the active link underline
    let activeUnderlineWidth = activeLink.offsetWidth;
    let activeUnderlineOffset = activeLink.offsetLeft;

    // Set the initial underline position
    menu.style.setProperty("--underline-width", `${activeUnderlineWidth}px`);
    menu.style.setProperty("--underline-offset-x", `${activeUnderlineOffset}px`);

    // Adjust underline on hover
    links.forEach(link => {
        link.addEventListener("mouseover", (event) => {
            menu.style.setProperty("--underline-width", `${event.target.offsetWidth}px`);
            menu.style.setProperty("--underline-offset-x", `${event.target.offsetLeft}px`);
        });
    });

    // Reset underline to active link on mouse leave
    menu.addEventListener("mouseleave", () => {
        menu.style.setProperty("--underline-width", `${activeUnderlineWidth}px`);
        menu.style.setProperty("--underline-offset-x", `${activeUnderlineOffset}px`);
    });
});