How to close menu by clicking outside or anywhere on the page?

Asked

Viewed 1,250 times

4

Could someone help me get this menu to close when clicking outside, or anywhere on the page?

'Cause it’s closing just by clicking .button menu.

document.querySelector('.button').addEventListener('click', () => {
  document.querySelector('.sidebar').classList.toggle('isOpen');
});
@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100vh;
}

body {
  font: 500 .9rem/1 'Avenir Next', sans-serif;
  color: #333;
  background: #fff;
}

.wrapper {
  display: flex;
  min-height: 100%;
}

.sidebar {
  position: absolute;
  width: 220px;
  padding: 20px;
  transform: translateX(0);
  transition: transform .3s;
  background: #2f323e;
  height: 100vh;
}

.content {
  flex: 1;
  padding: 50px;
  background: #fff;
  box-shadow: 0 0 5px #000;
  transform: translateX(0);
  transition: transform .3s;
}

.sidebar.isOpen {
  transform: translateX(-220px);
}

.button {
  cursor: pointer;
}

.button svg {
  width: 40px;
}

.button line {
  stroke: black;
  stroke-width: 5;
}

h1 {
  margin-top: 25px;
  font-size: 40px;
  font-weight: 400;
}

.nav {
  list-style: none;
}

.nav li a {
  position: relative;
  display: block;
  margin-bottom: 5px;
  padding: 16px 0 16px 50px;
  color: #fff;
  border-radius: 4px;
  cursor: pointer;
}

.nav li a:hover,
.nav li a.active {
  background: rgba(0,0,0,.3);
}

.nav li a::before {
  font: 14px fontawesome;
  position: absolute;
  top: 15px;
  left: 20px;
}

.nav li:nth-child(1) a::before { content: '\f00a'; }
.nav li:nth-child(2) a::before { content: '\f012'; }
.nav li:nth-child(3) a::before { content: '\f0e8'; }
.nav li:nth-child(4) a::before { content: '\f0c3'; }
.nav li:nth-child(5) a::before { content: '\f022'; }
.nav li:nth-child(6) a::before { content: '\f115'; }
.nav li:nth-child(7) a::before { content: '\f085'; }
.nav li:nth-child(8) a::before { content: '\f023'; left: 23px; }
<div class="wrapper">
  <div class="sidebar isOpen">

      <a class="button" style="margin: 0px 0px 0px 215px;  position: absolute;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
            <line x1="0" y1="20" x2="100" y2="20" />
            <line x1="0" y1="50" x2="100" y2="50" />
            <line x1="0" y1="80" x2="100" y2="80" />
         </svg>
        </a>
        
    <ul class="nav">
      <li><a class="active">Dashboard</a></li>
      <li><a>Charts</a></li>
      <li><a>Milestones</a></li>
      <li><a>Lab</a></li>
      <li><a>Preview</a></li>
      <li><a>Assets</a></li>
      <li><a>Settings</a></li>
      <li><a>Logout</a></li>
    </ul> 
  </div>
   
</div>

2 answers

5


You can at the same time open the sidebar tb "open" an element behind the sidebar that will cover the entire screen and will serve to close the menu if it is clicked. I called this element from .fechaMenu and when you click to open the navbar it appears, and if you click it it disappears and closes the navbar. That’s why I used the toggle class with class .isClose who has a display:none to remove the .fechaMenu

I put a z-index of 2 in navbar and 1 no .fechaMenu, so it always opens over everything below, just doesn’t get above the .navbar

inserir a descrição da imagem aqui

As you will see in JS the principle used is the same that you used in btn of hamburger menu I left the .fechaMenu with a color, but you can make it completely transparent in CSS just put rgba(0,0,0,0) in the color of background that it is not visible, but remains active and closing the navbar correctly.

I left the comments in the code

document.querySelector('.button').addEventListener('click', () => {
  document.querySelector('.sidebar').classList.toggle('isOpen');
  document.querySelector('.fechaMenu').classList.toggle('isClose');
});

// eventos para fechar o menu, ele basicamente faz o inverso do script anterior
//quando vc clicar no elemento .fechaMenu

document.querySelector('.fechaMenu').addEventListener('click', () => {
  document.querySelector('.sidebar').classList.toggle('isOpen');
  document.querySelector('.fechaMenu').classList.toggle('isClose');
});
@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100vh;
}

body {
  font: 500 .9rem/1 'Avenir Next', sans-serif;
  color: #333;
  background: #fff;
}

.wrapper {
  display: flex;
  min-height: 100%;
}

.sidebar {
  position: absolute;
  width: 220px;
  padding: 20px;
  transform: translateX(0);
  transition: transform .3s;
  background: #2f323e;
  height: 100vh;

  z-index: 2;
}

.content {
  flex: 1;
  padding: 50px;
  background: #fff;
  box-shadow: 0 0 5px #000;
  transform: translateX(0);
  transition: transform .3s;
}

.sidebar.isOpen {
  transform: translateX(-220px);
}

.button {
  cursor: pointer;
}

.button svg {
  width: 40px;
}

.button line {
  stroke: black;
  stroke-width: 5;
}

h1 {
  margin-top: 25px;
  font-size: 40px;
  font-weight: 400;
}

.nav {
  list-style: none;
}

.nav li a {
  position: relative;
  display: block;
  margin-bottom: 5px;
  padding: 16px 0 16px 50px;
  color: #fff;
  border-radius: 4px;
  cursor: pointer;
}

.nav li a:hover,
.nav li a.active {
  background: rgba(0,0,0,.3);
}

.nav li a::before {
  font: 14px fontawesome;
  position: absolute;
  top: 15px;
  left: 20px;
}

.nav li:nth-child(1) a::before { content: '\f00a'; }
.nav li:nth-child(2) a::before { content: '\f012'; }
.nav li:nth-child(3) a::before { content: '\f0e8'; }
.nav li:nth-child(4) a::before { content: '\f0c3'; }
.nav li:nth-child(5) a::before { content: '\f022'; }
.nav li:nth-child(6) a::before { content: '\f115'; }
.nav li:nth-child(7) a::before { content: '\f085'; }
.nav li:nth-child(8) a::before { content: '\f023'; left: 23px; }

/* classes do elemento que vai abrir por baixo da navbar e se clicado fecha o menu */
.fechaMenu {
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,.5);
  position: fixed;
  top: 0;
  left: 0;

  z-index: 1;
}
.isClose {
  display: none;
}
<div class="wrapper">
  <div class="sidebar isOpen">

      <a class="button" style="margin: 0px 0px 0px 215px;  position: absolute;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
            <line x1="0" y1="20" x2="100" y2="20" />
            <line x1="0" y1="50" x2="100" y2="50" />
            <line x1="0" y1="80" x2="100" y2="80" />
         </svg>
        </a>

    <ul class="nav">
      <li><a class="active">Dashboard</a></li>
      <li><a>Charts</a></li>
      <li><a>Milestones</a></li>
      <li><a>Lab</a></li>
      <li><a>Preview</a></li>
      <li><a>Assets</a></li>
      <li><a>Settings</a></li>
      <li><a>Logout</a></li>
    </ul> 
  </div>
<!-- elemento que quando o menu abre ele aparece, e se clicado ele some e fecha o menu -->
  <div class="fechaMenu isClose"></div>
</div>

  • very good my friend, thank you very much for the help, ball show!

  • @Andrémalveira glad it worked out! If any answer has helped you in any way consider marking it as Accept, in this icon below the arrows on the left side of the answer :) So the site does not get open questions pending without accepted answer. Just vc choose the answer you believe best solved your problem and mark the , vc can only mark an answer unfortunately.

2

You can check if the click originated from outside the sidebar by creating a Event Handler to the window object when any element of the page is clicked (see explanatory comments in the code):

document.querySelector('.button').addEventListener('click', () => {
   document.querySelector('.sidebar').classList.toggle('isOpen');
});

window.onclick = (e) =>{
   
   // seleciona o .sidebar
   let sid = document.querySelector('.sidebar');
   
   // verifica se está fechado ou aberto
   let ope = sid.classList.contains('isOpen');

   // verifica se o elemento clicado contém a classe .sidebar
   let alv = e.target.classList.contains('sidebar');
   
   // verifica se o elemento clicado é filho de .sidebar
   let pai = e.target.closest('.sidebar');

   // se tudo for falso, fecha o sidebar
   if(!ope && !alv && !pai) sid.classList.toggle('isOpen');
   
}
@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100vh;
}

body {
  font: 500 .9rem/1 'Avenir Next', sans-serif;
  color: #333;
  background: #fff;
}

.wrapper {
  display: flex;
  min-height: 100%;
}

.sidebar {
  position: absolute;
  width: 220px;
  padding: 20px;
  transform: translateX(0);
  transition: transform .3s;
  background: #2f323e;
  height: 100vh;
}

.content {
  flex: 1;
  padding: 50px;
  background: #fff;
  box-shadow: 0 0 5px #000;
  transform: translateX(0);
  transition: transform .3s;
}

.sidebar.isOpen {
  transform: translateX(-220px);
}

.button {
  cursor: pointer;
}

.button svg {
  width: 40px;
}

.button line {
  stroke: black;
  stroke-width: 5;
}

h1 {
  margin-top: 25px;
  font-size: 40px;
  font-weight: 400;
}

.nav {
  list-style: none;
}

.nav li a {
  position: relative;
  display: block;
  margin-bottom: 5px;
  padding: 16px 0 16px 50px;
  color: #fff;
  border-radius: 4px;
  cursor: pointer;
}

.nav li a:hover,
.nav li a.active {
  background: rgba(0,0,0,.3);
}

.nav li a::before {
  font: 14px fontawesome;
  position: absolute;
  top: 15px;
  left: 20px;
}

.nav li:nth-child(1) a::before { content: '\f00a'; }
.nav li:nth-child(2) a::before { content: '\f012'; }
.nav li:nth-child(3) a::before { content: '\f0e8'; }
.nav li:nth-child(4) a::before { content: '\f0c3'; }
.nav li:nth-child(5) a::before { content: '\f022'; }
.nav li:nth-child(6) a::before { content: '\f115'; }
.nav li:nth-child(7) a::before { content: '\f085'; }
.nav li:nth-child(8) a::before { content: '\f023'; left: 23px; }
<div class="wrapper">
  <div class="sidebar isOpen">

      <a class="button" style="margin: 0px 0px 0px 215px;  position: absolute;">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
            <line x1="0" y1="20" x2="100" y2="20" />
            <line x1="0" y1="50" x2="100" y2="50" />
            <line x1="0" y1="80" x2="100" y2="80" />
         </svg>
        </a>
        
    <ul class="nav">
      <li><a class="active">Dashboard</a></li>
      <li><a>Charts</a></li>
      <li><a>Milestones</a></li>
      <li><a>Lab</a></li>
      <li><a>Preview</a></li>
      <li><a>Assets</a></li>
      <li><a>Settings</a></li>
      <li><a>Logout</a></li>
    </ul> 
  </div>
   
</div>

  • very good tbm my friend, thanks for your help, this tbm ta ball show!

  • You’re welcome, pal! Good luck in your codes! D

Browser other questions tagged

You are not signed in. Login or sign up in order to post.