Chaz Steiner
Chaz Steiner

Reputation: 527

Click Outside To close slide menu Javascript

Hi I see similar questions but nothing that can help me, I have a javascript menu, and I want to click outside the menu to close it, right now, you must click the X to close the menu, I want to be able to click anywhere on the page, outside the menu, to close the menu.

<head>
<style>
.sidenav {
       height: 100%;
       width: 0;
      position: fixed;
      z-index: 1;
      top: 0;
      left: 0;
      background-color: #111;
      overflow-x: hidden;
      transition: 0.5s;
      padding-top: 60px;
    }
    
    .sidenav a {
      padding: 8px 8px 8px 32px;
      text-decoration: none;
      font-size: 25px;
      color: #818181;
      display: block;
      transition: 0.3s;
    }
    
    .sidenav a:hover {
      color: #f1f1f1;
    }
    
    .sidenav .closebtn {
      position: absolute;
      top: 0;
      right: 25px;
      font-size: 36px;
      margin-left: 50px;
    }
    
    @media screen and (max-height: 450px) {
      .sidenav {padding-top: 15px;}
      .sidenav a {font-size: 18px;}
    }
    </style>
    </head>
    <body>
    
    <div id="mySidenav" class="sidenav">
      <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
      <a href="#">About</a>
      <a href="#">Services</a>
      <a href="#">Clients</a>
      <a href="#">Contact</a>
    </div>
    
    <h2>Animated Sidenav Example</h2>
    <p>Click on the element below to open the side navigation menu.</p>
    <span style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776; open</span>
    
    <script>
    function openNav() {
      document.getElementById("mySidenav").style.width = "250px";
    }
    
    function closeNav() {
      document.getElementById("mySidenav").style.width = "0";
    }
    </script>
  

Upvotes: 0

Views: 906

Answers (3)

Andrei
Andrei

Reputation: 1

This is an accessible solution, as far as how to handle the hamburger menu itself. You wrap the child content in the slide-in menu in a div and apply the display:none rule to that. Add all aria-labels and such to that div. Apply the animations to the div that wraps around the one with display:none rule. That way, the markup changes on slide-in menu close and the screen readers will read the button but not its menu content, unless, of course you click on it and the display:none rule is removed. If the div in which the nav button is inserted has a role="status" then the SR should read the contents of the newly added menu the moment it's displayed in the UI. Hope it helps!

function openNav() {
  document.body.classList.add('sidenav-open');
  var element = document.getElementById("sideNavContent");
  element.classList.remove("sidenav-closed");
}

function closeNav() {
  document.body.classList.remove('sidenav-open');
  var element = document.getElementById("sideNavContent");
  element.classList.add("sidenav-closed");
}
.sidenav {
    height: 100%;
    width: 0;
    position: fixed;
    z-index: 90;
    top: 0;
    right: 0;
    background-color: black;
    overflow-x: hidden;
    transition: 0.5s;
    padding-top: 60px;
}

.sidenav a {
    padding: 8px 8px 8px 32px;
    text-decoration: none;
    font-size: 25px;
    color: #818181;
    display: block;
    transition: .3s
}

.sidenav a:hover {
    color: #f1f1f1;
}

.sidenav .closebtn {
    position: absolute;
    top: 0;
    right: 25px;
    font-size: 36px;
    margin-left: 50px
}

@media screen and (max-height:450px) {
    .sidenav {
        padding-top: 15px;
    }

    .sidenav a {
        font-size: 18px;
    }
}

#sidenav-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 0;
    height: 100%;
    background: rgba(0, 0, 0, .75);
    cursor: pointer;
    z-index: 90;
}

.sidenav-open .sidenav {
    width: 90vw;
    display: block;
    animation: fade-in-show 0.5s;
}

.sidenav-open #sidenav-overlay {
    width: 100%;
    animation: fade-in-show 0.5s;
}

.sidenav-closed {
    display: none;
}
<button style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776;</button>

        <div id="sidenav-overlay" onclick="closeNav()"></div>
        <div id="mySidenav" class="sidenav">
          <div id="sideNavContent">
          <a href="#" class="closebtn" onclick="closeNav()">&times;</a>
          <a href="#">About</a>
          <a href="#">Services</a>
          <a href="#">Clients</a>
          <a href="#">Contact</a>
        </div>
        </div>

Upvotes: 0

blex
blex

Reputation: 25659

You could listen for clicks and check where the target is, or just create an overlay all over the page, and use a class for the open menu, instead of manually setting the sidenav width:

function openNav() {
  document.body.classList.add('sidenav-open');
}

function closeNav() {
  document.body.classList.remove('sidenav-open');
}
/* Same as you */.sidenav{height:100%;width:0;position:fixed;z-index:1;top:0;left:0;background-color:#111;overflow-x:hidden;transition:.5s;padding-top:60px}.sidenav a{padding:8px 8px 8px 32px;text-decoration:none;font-size:25px;color:#818181;display:block;transition:.3s}.sidenav a:hover{color:#f1f1f1}.sidenav .closebtn{position:absolute;top:0;right:25px;font-size:36px;margin-left:50px}@media screen and (max-height:450px){.sidenav{padding-top:15px}.sidenav a{font-size:18px}}

#sidenav-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 100%;
  background: rgba(0, 0, 0, .1);
  cursor: pointer;
  z-index: 1;
}
.sidenav-open .sidenav { width: 250px; }
.sidenav-open #sidenav-overlay { width: 100%; }
<div id="sidenav-overlay" onclick="closeNav()"></div>
<div id="mySidenav" class="sidenav">
  <a href="#" class="closebtn" onclick="closeNav()">&times;</a>
  <a href="#">About</a>
  <a href="#">Services</a>
  <a href="#">Clients</a>
  <a href="#">Contact</a>
</div>

<h2>Animated Sidenav Example</h2>
<p>Click on the element below to open the side navigation menu.</p>
<span style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776; open</span>

Upvotes: 1

Scott Marcus
Scott Marcus

Reputation: 65835

Set up a click event listener on the document and, in the listener, check to see if the actual click came from anything that isn't the menu.

<head>
<style>
.sidenav {
       height: 100%;
       width: 0;
      position: fixed;
      z-index: 1;
      top: 0;
      left: 0;
      background-color: #111;
      overflow-x: hidden;
      transition: 0.5s;
      padding-top: 60px;
    }
    
    .sidenav a {
      padding: 8px 8px 8px 32px;
      text-decoration: none;
      font-size: 25px;
      color: #818181;
      display: block;
      transition: 0.3s;
    }
    
    .sidenav a:hover {
      color: #f1f1f1;
    }
    
    .sidenav .closebtn {
      position: absolute;
      top: 0;
      right: 25px;
      font-size: 36px;
      margin-left: 50px;
    }
    
    @media screen and (max-height: 450px) {
      .sidenav {padding-top: 15px;}
      .sidenav a {font-size: 18px;}
    }
    </style>
    </head>
    <body>
    
    <div id="mySidenav" class="sidenav">
      <a href="#" class="closebtn" onclick="closeNav()">&times;</a>
      <a href="#">About</a>
      <a href="#">Services</a>
      <a href="#">Clients</a>
      <a href="#">Contact</a>
    </div>
    
    <h2>Animated Sidenav Example</h2>
    <p>Click on the element below to open the side navigation menu.</p>
    <span id="open" style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776; open</span>
    
    <script>
    function openNav() {
      document.getElementById("mySidenav").style.width = "250px";
    }
    
    function closeNav() {
      document.getElementById("mySidenav").style.width = "0";
    }
    
    let sidebar = document.getElementById("mySidenav");
    let open = document.getElementById("open");
    document.addEventListener("click", function(event){
      // If the event didn't originate from the open button or the sidebar, close it
      if(event.target !== sidebar && event.target !== open){
        closeNav();
      }
    });
    </script>

Upvotes: 1

Related Questions