Addressing issue with disappearing li elements in navbar (HTML, CSS, JS)

Viewed 57

document.addEventListener("DOMContentLoaded", () => {
  let menuBtn = document.querySelector("#menu-button");
  let menu = document.querySelector("#menu");
  let menuItems = menu.getElementsByTagName("li");

  menuBtn.addEventListener("click", e => {
    if (e.target.innerText === ("✕")) {
      e.target.innerText = "☰";
      [...menuItems].forEach(item => item.style.display = "none");
    } else if (e.target.innerText === "☰") {
      e.target.innerText = "✕";
      [...menuItems].forEach(item => item.style.display = "block");
    }
  });
});
  header {
  width: 100%;
  height: 100px;
}

#menu {
  display: flex;
  flex-direction: row;
  margin: 0 auto;
  justify-content: space-around;
  font-size: 2rem;
}

#menu-button {
  display: none;
}

li {
  list-style-type: none;
}

a {
  text-decoration: none;
  color: rgb(0, 0, 0);
}

@media screen and (max-width: 1050px) {
  #menu {
    flex-direction: column;
    width: 100%;
    height: 100%;
  }
  #menu li {
    padding: 1.5rem;
    display: none;
  }
  #menu-button {
    display: block;
    font-size: 3rem;
    cursor: pointer;
    outline: none;
    border: none;
  }
}
<header>
  <nav>
    <button id="menu-button">☰</button>
    <ul id="menu">
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>
</header>

It's a simple nav menu with desktop-first approach that uses flexbox.

  1. Viewport is less than 1050px and therefore shows hamburger button
  2. Hamburger button is clicked to show menu in dropdown form. Hamburger button changes to "X".
  3. "X" is clicked. The JS code changes all li elements to display: none
  4. PROBLEM: Viewport is increased beyond breakpoint of 1050px. Since li elements were changed to display: none, menu is not shown.

Would appreciate suggestions on how to address this.

Also, smaller but nagging issue.

  1. Viewport is less than 1050px and therefore shows hamburger button
  2. Hamburger button is clicked to show menu in dropdown form. Hamburger button changes to "X".
  3. Viewport is increased beyond breakpoint of 1050p and then back below breakpoint. Since all li elements were set to display: block in JS code, the dropdown menu appears. I'd like to make it so that the hamburger icon appears whenever viewport size is decreased.

Thanks for all and any help!

1 Answers

Add & remove CSS classes instead of setting the inline style. Doing this will give CSS more control. Inline styles can only be overwritten by using !important and that will make it even harder to overwrite.

Instead of showing and hiding every individual <li>, only hide the parent <ul>. That will also hide all the children inside of it.

The example below adds and removes an active class to the #menu element when clicking the menu button. This active class shows the #menu on mobile where it is hidden. On larger screens, #menu is always shown.

document.addEventListener("DOMContentLoaded", () => {
  let menuBtn = document.querySelector("#menu-button");
  let menu = document.querySelector("#menu");

  // First question: 
  // Add a class instead of inline styles.
  menuBtn.addEventListener("click", e => {
    if (e.target.innerText === ("✕")) {
      e.target.innerText = "☰";
      menu.classList.remove('active');
    } else if (e.target.innerText === "☰") {
      e.target.innerText = "✕";
      menu.classList.add('active');
    }
  });
  
  // Second question:
  // Watch a media query, reset the button and hide the 
  // menu when changing from large to a small size.
  const mediaQuery = window.matchMedia('screen and (max-width: 1050px)');
  mediaQuery.addEventListener('change', ({ matches }) => {
    if (!matches) return;
    menuBtn.innerText = "☰";
    menu.classList.remove('active');
  });
});
header {
  width: 100%;
  height: 100px;
}

#menu {
  display: flex;
  flex-direction: row;
  margin: 0 auto;
  justify-content: space-around;
  font-size: 2rem;
}

#menu-button {
  display: none;
}

li {
  list-style-type: none;
}

a {
  text-decoration: none;
  color: rgb(0, 0, 0);
}

@media screen and (max-width: 1050px) {
  #menu {
    display: none;
    flex-direction: column;
    width: 100%;
    height: 100%;
  }
  
  #menu.active {
    display: flex;
  }

  #menu li {
    padding: 1.5rem;
  }
  
  #menu-button {
    display: block;
    font-size: 3rem;
    cursor: pointer;
    outline: none;
    border: none;
  }
<header>
  <nav>
    <button id="menu-button">☰</button>
    <ul id="menu">
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>
</header>

Related