1

So i just copied code from this answer and it doesn't seem to work. I can't find out why.

Current behavior: after opening menu and clicking outside of it nothing happens (class 'openMenu' stays)

Expected behavior: after opening menu and clicking outside of it menu closes (class openMenu removes)

var navToggle = document.getElementById("menu-trigger");
var navMenu = document.getElementById("header-menu");
var isMouseDown = false;

navToggle.addEventListener('click', function() {
  this.focus();
  navMenu.classList.toggle('openMenu');
  navMenu.focus();
});

navMenu.addEventListener('mousedown', function() {
  isMouseDown = true;  
});

navMenu.addEventListener('mouseup', function() {
  isMouseDown = false;  
});

navMenu.addEventListener('mouseleave', function() {
  isMouseDown = false;  
});

navMenu.addEventListener('blur', function() {
  if (!isMouseDown) {
    navMenu.classList.remove('openMenu');
  }
}, true);
header i.fa-bars {
  position: absolute;
  right: 0;
  margin: 5px;
  font-size: 1rem;
  cursor: pointer;
}

header nav ul {
  position: absolute;
  top: 0;
  left: 0;
  -webkit-transform: translateX(-150%);
          transform: translateX(-150%);
  -webkit-transition: .5s all;
  transition: .5s all;
  padding: 10px;
  width: 50vw;
  font-size: 2rem;
  background-color: #1f2a3e;
  height: 100%;
  z-index: 99;
  margin: 0 auto;
  display: -ms-grid;
  display: grid;
  -ms-grid-rows: (minmax(50px, 1fr))[auto-fill];
      grid-template-rows: repeat(auto-fill, minmax(50px, 1fr));
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
}

header nav ul.openMenu {
  -webkit-transform: translateX(0);
          transform: translateX(0);
  -webkit-transition: .5s all;
  transition: .5s all;
}
  <header>
    <i class="fas fa-bars" id="menu-trigger">fontawesome menu icon</i>
    <nav>
      <ul id="header-menu">
        <li><a href="">Главная</a></li>
        <li><a href="">Кейсы</a></li>
        <li><a href="">Услуги</a></li>
        <li><a href="">Отзывы</a></li>
        <li><a href="">Контакты</a></li>
      </ul>
    </nav>
  </header>

Trying to implement this for three hours, tried every available solution but everything failed. What am I doing wrong? How do I accomplish it?

Thank you, Mister @epascarello for the working solution.

3 Answers3

1

Add a click handler to the body, check to see where the event came from. If it is not the nav, hide it.

var navToggle = document.getElementById("menu-trigger");
var navMenu = document.getElementById("header-menu");

navToggle.addEventListener('click', function() {
  this.focus();
  navMenu.classList.toggle('openMenu');
});

document.querySelector("body").addEventListener("click", function(evt) {
  if (!navMenu.classList.contains('openMenu')) return;
  var isNav = navMenu.contains(evt.target) || navToggle.contains(evt.target);
  if (!isNav) {
    navMenu.classList.remove('openMenu');
  }

})
header i.fa-bars {
  position: absolute;
  right: 0;
  margin: 5px;
  font-size: 1rem;
  cursor: pointer;
}

header nav ul {
  position: absolute;
  top: 0;
  left: 0;
  -webkit-transform: translateX(-150%);
  transform: translateX(-150%);
  -webkit-transition: .5s all;
  transition: .5s all;
  padding: 10px;
  width: 50vw;
  font-size: 2rem;
  background-color: #1f2a3e;
  height: 100%;
  z-index: 99;
  margin: 0 auto;
  display: -ms-grid;
  display: grid;
  -ms-grid-rows: (minmax(50px, 1fr))[auto-fill];
  grid-template-rows: repeat(auto-fill, minmax(50px, 1fr));
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
}

header nav ul.openMenu {
  -webkit-transform: translateX(0);
  transform: translateX(0);
  -webkit-transition: .5s all;
  transition: .5s all;
}
<header>
  <i class="fas fa-bars" id="menu-trigger">fontawesome menu icon</i>
  <nav>
    <ul id="header-menu">
      <li><a href="">Главная</a></li>
      <li><a href="">Кейсы</a></li>
      <li><a href="">Услуги</a></li>
      <li><a href="">Отзывы</a></li>
      <li><a href="">Контакты</a></li>
    </ul>
  </nav>
</header>
<h1>Hello World</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ultricies tellus fringilla enim eleifend aliquam. Nulla non imperdiet metus, quis tincidunt nunc. Nullam arcu elit, tincidunt et mauris a, dapibus interdum sapien. Curabitur sollicitudin leo nibh, sed maximus dui hendrerit nec. Vivamus sed urna vel mauris sodales eleifend in vel urna. Nunc pulvinar non turpis in fringilla. Sed ac iaculis turpis. Aliquam condimentum mollis nunc, eu feugiat sem interdum a. Pellentesque efficitur velit fermentum tristique molestie. Donec sed volutpat magna, id consequat nulla. In nec enim nulla. Cras in lacus tincidunt, feugiat lorem in, eleifend tellus. Mauris eget lectus urna. Duis quis nulla eget massa fringilla elementum nec id eros.</p>
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Could you explain your code please? `if (!navMenu.classList.contains('openMenu')) return;` - if navMenu doesn't have `openMenu` class do nothing, right? I don't understand what this string does `var isNav = navMenu.contains(evt.target) || navToggle.contains(evt.target);` what is `evt` in this case? A `click` event? What value does `isNav` have after click occurs? – PYTHON DEVELOPER999 Jul 16 '20 at 10:13
  • 1
    If there is no class on the element, exit our because we do not care since menu is not open. The variable. evt is the event object. target is the DOM element that was clicked. And documentation for contains: https://developer.mozilla.org/en-US/docs/Web/API/Node/contains#:~:text=contains()%20method%20returns%20a,direct%20children%2C%20and%20so%20on. – epascarello Jul 16 '20 at 12:53
1

My previous answer wasn't as specific. Here is a new one. The HTML you should add is this:

<span id="page"></span>

Here is the javascript:

var page = document.getElementById('page');
page.style.width = window.innerWidth;
page.style.height = window.innerHeight;
page.addEventListener('click', function() {
    this.focus();
    navMenu.classList.hide('openMenu');
    navMenu.focus();
});
Saiansh Singh
  • 583
  • 5
  • 16
0

Create a new span element. Make it so that it covers the whole screen using window.innerWidth and window.innerHeight. Now, add an id and reference to the span in your javascript. Instead of using the click event listener on the navToggle, put it on the span. This will implement the behavior.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Saiansh Singh
  • 583
  • 5
  • 16