gjjr
gjjr

Reputation: 569

Click anywhere outside of menu to close menu

Even after reading about 20 related questions/threads on here I just cannot figure this out, been trying things for hours but just cant get it, so really hoping someone can put me out of my misery!

I have a slide out menu that currently requires the user to click on the "X" to close it, I need to make it possible for users to click anywhere outside of the menu OR on the "X" to close it.

Ive created a codepen to make it easier to look at the code as theres quite a lot of it.

jQuery(document).ready(function($){
    $('.btn-open-menu').click(function () {
        $('header').addClass('open');
     $('html').addClass('open');
      $('html, body').addClass('noscroll');

    });

    $('.link-menu').click(function () {
        $('header').removeClass('open');
      $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $('.btn-close-menu').click(function () {
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });
  
      $('.btn-open-menu2').click(function () {
        $('header').addClass('open');
     $('html').addClass('open');
        $('html, body').addClass('noscroll');
    });

    $('.link-menu').click(function () {
        $('header').removeClass('open');
      $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $('.btn-close-menu2').click(function () {
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });



});
 header {
     width: 100%;
     
     background-color: transparent;
     position: fixed;
     top: 0;
     left: 0;
     z-index: 10;
     transition: 0.5s ease-in-out;
}


 header .btn-open-menu {
     width: 25px;
     height: 25px;
     position: absolute;
     top: 50px;
     right: 50px;
     cursor: pointer;
}

@media only screen and (max-width: 767px) {
    header .btn-open-menu {
     top: 25px;
     right: 20px;
}
}

@media only screen and (max-width: 767px) {
     header .header-content {
     width: 100% !important;
     }
}
 header .header-content {
     width: 30%;
     height: 100vh;
      height: calc(var(--vh, 1vh) * 100);
     background-color: #FB4D98;
     box-sizing: border-box;
     position: absolute;
     top: 0;
         left:initial; right: -100%;
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: column;
     align-content: center;
     transition: 0.8s ease-in-out;
}


@media only screen and (max-width: 767px) {
     header .header-content .btn-close-menu {
     top: 20px !important;
     right: 20px !important;
     }
}

 header .header-content .btn-close-menu {
     width: 25px;
     height: 25px;
     position: absolute;
     top: 50px;
     right: 50px;
     cursor: pointer;
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: row;
     align-content: center;
}
 header .header-content .btn-close-menu:before, header .header-content .btn-close-menu:after {
     background: #F4FB82;
     content: '';
     display: block;
     width: 100%;
     height: 4px;
     position: absolute;
     transition: 0.5s ease-in-out;
}
 header .header-content .btn-close-menu:before {
     transform: rotate(45deg);
}

 header .header-content .btn-close-menu:hover{
     transform: rotate(180deg);
     transition:0.5s ease-in-out;
     
}

 header .header-content .btn-close-menu:after {
     transform: rotate(-45deg);
}

 header .header-content nav {
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: column;
     align-content: center;
}
 header .header-content nav a {
     color: #000;
     letter-spacing: 0.5px;
     line-height: 35px;
     text-decoration: none;
     transition: 0.5s;
}
 header .header-content nav a:hover {
     color: rgba(0, 0, 0, 0.5);
     transition: 1s;
}
 header .header-content .social {
     display: flex;
     justify-content: center;
     align-items: center;
     margin: 40px 0 0 0;
     font-size: 20px;
}
 header .header-content .social a {
     color: #000;
     text-decoration: none;
     margin: 0 10px;
     transition: 0.5s;
}
 header .header-content .social a:hover {
     color: #F4FB82;
     transform: scale(1.5);
     transition: 0.5s;
}


 header.open {
     height: 100vh;
     background-color: rgba(0, 0, 0, 0.5);
     transition: 0.5s ease-in-out;
}
 header.open .btn-open-menu, header.open .logo {
     opacity: 0;
     transition: 1s ease-in-out;
}
 header.open .header-content {
     left:initial; right: 0;
     transition: 0.8s ease-in-out;
}

 .Menu-list {
     font-family: "alliance";
     font-size: 4vw;
     line-height: 1.2;
     text-transform: uppercase;
     text-align: center;
     display: flex;
     flex-direction: column;
     align-items: center;
}

@media only screen and (max-width: 767px) {
     .Menu-list {
     font-family: "alliance";
     font-size: 12vw;
     }
}
 .Menu-list-item {
     position: relative;
     color: transparent;
     cursor: pointer;
}

 ul.Menu-list{
     padding-inline-start: 0px !important;
     
 }
 .Menu-list-item::before {
     content: '';
     display: block;
     position: absolute;
     top: 49%;
     left: -10%;
     right: -10%;
     height: 4px;
     border-radius: 4px;
     margin-top: -2px;
     background: #F4FB82;
     transform: scale(0);

     z-index: 1;
}
  .Mask {
     display: block;
     position: absolute;
     overflow: hidden;
     padding-right: 5px;
     padding-left: 5px;
     color: #F4FB82;
     top: 0;
     height: 49%;
     transition: all 1s cubic-bezier(0.16, 1.08, 0.38, 0.98);
}

@media only screen and (max-width: 767px) {
     .Mask {
    transition: all 0.2s cubic-bezier(0.16, 1.08, 0.38, 0.98);
     }
}
 .Mask span {
     display: block;
}
 .Mask + .Mask {
     top: 48.9%;
     height: 51.1%;
}
 .Mask + .Mask span {
     transform: translateY(-49%);
}
 .Menu-list-item:hover .Mask, .Menu-list-item:active .Mask {
     color: #000;
     transform: skewX(12deg) translateX(5px);
}
 .Menu-list-item:hover .Mask + .Mask, .Menu-list-item:active .Mask + .Mask {
     transform: skewX(12deg) translateX(-5px);
}
 .Menu-list-item:hover::before, .Menu-list-item:active::before {
     transform: scale(1);
}

  
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
  <a class="btn-open-menu">
    <span class="hamburguer"><img src="https://upload.wikimedia.org/wikipedia/commons/b/b2/Hamburger_icon.svg"></span>
  </a>
  
  <div class="header-content">
    <a class="btn-close-menu"></a>

    <nav>
     <div class="Menu">
  <ul class="Menu-list" data-offset="10">
    <li class="Menu-list-item" data-offset="20" onclick="location.href='/home';">
      Home
      <span class="Mask"><span>Home</span></span>
      <span class="Mask"><span>Home</span></span>
    </li>
    <li class="Menu-list-item" data-offset="16" onclick="location.href='/about';">
      About
      <span class="Mask"><span>About</span></span>
      <span class="Mask"><span>About</span></span>
    </li>
    <li class="Menu-list-item" data-offset="12" onclick="location.href='/contact';">
      Contact
      <span class="Mask"><span>Contact</span></span>
      <span class="Mask"><span>Contact</span></span>
    </li>

  </ul>
</div>
       </nav>
   
</header>

Upvotes: 2

Views: 3687

Answers (4)

Irvin Dominin
Irvin Dominin

Reputation: 30993

You can simplify this by using stopPropagation in your open click handler, and close the menu in a generic click header handler.

Code

    $('.btn-open-menu').click(function (e) {
      $('header').addClass('open');
      $('html').addClass('open');
      $('html, body').addClass('noscroll');
      e.stopPropagation();
    });

You can let the menu open, by clicking on the background using:

  $(".header-content").click(function (e) {
    e.stopPropagation();
  });

Ref: https://api.jquery.com/event.stoppropagation/

Demo

Upvotes: 2

Maria Nirmal
Maria Nirmal

Reputation: 383

A better way to do it is creating an overlay element behind the header and hide it and the menu when it is clicked.

jQuery(document).ready(function($){
    $('.btn-open-menu').click(function () {
        $('header').addClass('open');
     $('html').addClass('open');
      $('html, body').addClass('noscroll');

    });

    $('.link-menu').click(function () {
        $('header').removeClass('open');
      $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $('.btn-close-menu').click(function () {
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });
  
      $('.btn-open-menu2').click(function () {
        $('header').addClass('open');
     $('html').addClass('open');
        $('html, body').addClass('noscroll');
    });

    $('.link-menu').click(function () {
        $('header').removeClass('open');
      $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $('.btn-close-menu2').click(function () {
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });
    
    $('.overlay').click(function () {
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });



});
 header {
     width: 100%;
     
     background-color: transparent;
     position: fixed;
     top: 0;
     left: 0;
     z-index: 10;
     transition: 0.5s ease-in-out;
}


 header .btn-open-menu {
     width: 25px;
     height: 25px;
     position: absolute;
     top: 50px;
     right: 50px;
     cursor: pointer;
}

@media only screen and (max-width: 767px) {
    header .btn-open-menu {
     top: 25px;
     right: 20px;
}
}

@media only screen and (max-width: 767px) {
     header .header-content {
     width: 100% !important;
     }
}
 header .header-content {
     width: 30%;
     height: 100vh;
      height: calc(var(--vh, 1vh) * 100);
     background-color: #FB4D98;
     box-sizing: border-box;
     position: absolute;
     top: 0;
         left:initial; right: -100%;
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: column;
     align-content: center;
     transition: 0.8s ease-in-out;
}


@media only screen and (max-width: 767px) {
     header .header-content .btn-close-menu {
     top: 20px !important;
     right: 20px !important;
     }
}

 header .header-content .btn-close-menu {
     width: 25px;
     height: 25px;
     position: absolute;
     top: 50px;
     right: 50px;
     cursor: pointer;
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: row;
     align-content: center;
}
 header .header-content .btn-close-menu:before, header .header-content .btn-close-menu:after {
     background: #F4FB82;
     content: '';
     display: block;
     width: 100%;
     height: 4px;
     position: absolute;
     transition: 0.5s ease-in-out;
}
 header .header-content .btn-close-menu:before {
     transform: rotate(45deg);
}

 header .header-content .btn-close-menu:hover{
     transform: rotate(180deg);
     transition:0.5s ease-in-out;
     
}

 header .header-content .btn-close-menu:after {
     transform: rotate(-45deg);
}

 header .header-content nav {
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: column;
     align-content: center;
}
 header .header-content nav a {
     color: #000;
     letter-spacing: 0.5px;
     line-height: 35px;
     text-decoration: none;
     transition: 0.5s;
}
 header .header-content nav a:hover {
     color: rgba(0, 0, 0, 0.5);
     transition: 1s;
}
 header .header-content .social {
     display: flex;
     justify-content: center;
     align-items: center;
     margin: 40px 0 0 0;
     font-size: 20px;
}
 header .header-content .social a {
     color: #000;
     text-decoration: none;
     margin: 0 10px;
     transition: 0.5s;
}
 header .header-content .social a:hover {
     color: #F4FB82;
     transform: scale(1.5);
     transition: 0.5s;
}


 header.open .overlay{
   position:fixed;
   width:100vW;
     height: 100vh;
     background-color: rgba(0, 0, 0, 0.5);
     transition: 0.5s ease-in-out;
}
 header.open .btn-open-menu, header.open .logo {
     opacity: 0;
     transition: 1s ease-in-out;
}
 header.open .header-content {
     left:initial; right: 0;
     transition: 0.8s ease-in-out;
}

 .Menu-list {
     font-family: "alliance";
     font-size: 4vw;
     line-height: 1.2;
     text-transform: uppercase;
     text-align: center;
     display: flex;
     flex-direction: column;
     align-items: center;
}

@media only screen and (max-width: 767px) {
     .Menu-list {
     font-family: "alliance";
     font-size: 12vw;
     }
}
 .Menu-list-item {
     position: relative;
     color: transparent;
     cursor: pointer;
}

 ul.Menu-list{
     padding-inline-start: 0px !important;
     
 }
 .Menu-list-item::before {
     content: '';
     display: block;
     position: absolute;
     top: 49%;
     left: -10%;
     right: -10%;
     height: 4px;
     border-radius: 4px;
     margin-top: -2px;
     background: #F4FB82;
     transform: scale(0);

     z-index: 1;
}
  .Mask {
     display: block;
     position: absolute;
     overflow: hidden;
     padding-right: 5px;
     padding-left: 5px;
     color: #F4FB82;
     top: 0;
     height: 49%;
     transition: all 1s cubic-bezier(0.16, 1.08, 0.38, 0.98);
}

@media only screen and (max-width: 767px) {
     .Mask {
    transition: all 0.2s cubic-bezier(0.16, 1.08, 0.38, 0.98);
     }
}
 .Mask span {
     display: block;
}
 .Mask + .Mask {
     top: 48.9%;
     height: 51.1%;
}
 .Mask + .Mask span {
     transform: translateY(-49%);
}
 .Menu-list-item:hover .Mask, .Menu-list-item:active .Mask {
     color: #000;
     transform: skewX(12deg) translateX(5px);
}
 .Menu-list-item:hover .Mask + .Mask, .Menu-list-item:active .Mask + .Mask {
     transform: skewX(12deg) translateX(-5px);
}
 .Menu-list-item:hover::before, .Menu-list-item:active::before {
     transform: scale(1);
}

  .social {
     position: fixed;
     bottom: 60px;
}

 .copyright {
     position: fixed;
     bottom: 40px;
     font-family: "alliance";
     font-size: 14px;
     color: #0E0E0E;
     white-space: nowrap;
 }
 
  .privacy-policy {
     position: fixed;
     bottom: 20px;
     font-family: "alliance";
     font-size: 8px;
     color: #0E0E0E !important;
     white-space: nowrap;
 }
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
  <div class="overlay"></div>
  <a class="btn-open-menu">
    <span class="hamburguer"><img src="https://upload.wikimedia.org/wikipedia/commons/b/b2/Hamburger_icon.svg"></span>
  </a>
  
  <div class="header-content">
    <a class="btn-close-menu"></a>

    <nav>
     <div class="Menu">
  <ul class="Menu-list" data-offset="10">
    <li class="Menu-list-item" data-offset="20" onclick="location.href='/home';">
      Home
      <span class="Mask"><span>Home</span></span>
      <span class="Mask"><span>Home</span></span>
    </li>
    <li class="Menu-list-item" data-offset="16" onclick="location.href='/about';">
      About
      <span class="Mask"><span>About</span></span>
      <span class="Mask"><span>About</span></span>
    </li>
    <li class="Menu-list-item" data-offset="12" onclick="location.href='/contact';">
      Contact
      <span class="Mask"><span>Contact</span></span>
      <span class="Mask"><span>Contact</span></span>
    </li>

  </ul>
</div>
       </nav>
   
</header>

Upvotes: 2

Huy Phạm
Huy Phạm

Reputation: 1023

You can try this one. The one that you were missing is stopPropagation()

jQuery(document).ready(function($){
    $('.btn-open-menu').click(function (e) {
    e.stopPropagation();
        $('header').addClass('open');
     $('html').addClass('open');
      $('html, body').addClass('noscroll');

    });

    $('.link-menu').click(function () {
        $('header').removeClass('open');
      $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $('.btn-close-menu').click(function (e) {
     e.stopPropagation();
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });
  
      $('.btn-open-menu2').click(function () {
        $('header').addClass('open');
     $('html').addClass('open');
        $('html, body').addClass('noscroll');
    });

    $('.link-menu').click(function () {
        $('header').removeClass('open');
      $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $('.btn-close-menu2').click(function () {
        $('header').removeClass('open');
     $('html').removeClass('open');
      $('html, body').removeClass('noscroll');
      
    });

    $(document).click(function() {
      $('header').removeClass('open');
     $('html').removeClass('open');
     $('html, body').removeClass('noscroll');
});

});
header {
     width: 100%;
     
     background-color: transparent;
     position: fixed;
     top: 0;
     left: 0;
     z-index: 10;
     transition: 0.5s ease-in-out;
}


 header .btn-open-menu {
     width: 25px;
     height: 25px;
     position: absolute;
     top: 50px;
     right: 50px;
     cursor: pointer;
}

@media only screen and (max-width: 767px) {
    header .btn-open-menu {
     top: 25px;
     right: 20px;
}
}

@media only screen and (max-width: 767px) {
     header .header-content {
     width: 100% !important;
     }
}
 header .header-content {
     width: 30%;
     height: 100vh;
      height: calc(var(--vh, 1vh) * 100);
     background-color: #FB4D98;
     box-sizing: border-box;
     position: absolute;
     top: 0;
         left:initial; right: -100%;
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: column;
     align-content: center;
     transition: 0.8s ease-in-out;
}


@media only screen and (max-width: 767px) {
     header .header-content .btn-close-menu {
     top: 20px !important;
     right: 20px !important;
     }
}

 header .header-content .btn-close-menu {
     width: 25px;
     height: 25px;
     position: absolute;
     top: 50px;
     right: 50px;
     cursor: pointer;
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: row;
     align-content: center;
}
 header .header-content .btn-close-menu:before, header .header-content .btn-close-menu:after {
     background: #F4FB82;
     content: '';
     display: block;
     width: 100%;
     height: 4px;
     position: absolute;
     transition: 0.5s ease-in-out;
}
 header .header-content .btn-close-menu:before {
     transform: rotate(45deg);
}

 header .header-content .btn-close-menu:hover{
     transform: rotate(180deg);
     transition:0.5s ease-in-out;
     
}

 header .header-content .btn-close-menu:after {
     transform: rotate(-45deg);
}

 header .header-content nav {
     display: flex;
     flex-wrap: wrap;
     align-items: center;
     justify-content: center;
     flex-direction: column;
     align-content: center;
}
 header .header-content nav a {
     color: #000;
     letter-spacing: 0.5px;
     line-height: 35px;
     text-decoration: none;
     transition: 0.5s;
}
 header .header-content nav a:hover {
     color: rgba(0, 0, 0, 0.5);
     transition: 1s;
}
 header .header-content .social {
     display: flex;
     justify-content: center;
     align-items: center;
     margin: 40px 0 0 0;
     font-size: 20px;
}
 header .header-content .social a {
     color: #000;
     text-decoration: none;
     margin: 0 10px;
     transition: 0.5s;
}
 header .header-content .social a:hover {
     color: #F4FB82;
     transform: scale(1.5);
     transition: 0.5s;
}


 header.open {
     height: 100vh;
     background-color: rgba(0, 0, 0, 0.5);
     transition: 0.5s ease-in-out;
}
 header.open .btn-open-menu, header.open .logo {
     opacity: 0;
     transition: 1s ease-in-out;
}
 header.open .header-content {
     left:initial; right: 0;
     transition: 0.8s ease-in-out;
}

 .Menu-list {
     font-family: "alliance";
     font-size: 4vw;
     line-height: 1.2;
     text-transform: uppercase;
     text-align: center;
     display: flex;
     flex-direction: column;
     align-items: center;
}

@media only screen and (max-width: 767px) {
     .Menu-list {
     font-family: "alliance";
     font-size: 12vw;
     }
}
 .Menu-list-item {
     position: relative;
     color: transparent;
     cursor: pointer;
}

 ul.Menu-list{
     padding-inline-start: 0px !important;
     
 }
 .Menu-list-item::before {
     content: '';
     display: block;
     position: absolute;
     top: 49%;
     left: -10%;
     right: -10%;
     height: 4px;
     border-radius: 4px;
     margin-top: -2px;
     background: #F4FB82;
     transform: scale(0);

     z-index: 1;
}
  .Mask {
     display: block;
     position: absolute;
     overflow: hidden;
     padding-right: 5px;
     padding-left: 5px;
     color: #F4FB82;
     top: 0;
     height: 49%;
     transition: all 1s cubic-bezier(0.16, 1.08, 0.38, 0.98);
}

@media only screen and (max-width: 767px) {
     .Mask {
    transition: all 0.2s cubic-bezier(0.16, 1.08, 0.38, 0.98);
     }
}
 .Mask span {
     display: block;
}
 .Mask + .Mask {
     top: 48.9%;
     height: 51.1%;
}
 .Mask + .Mask span {
     transform: translateY(-49%);
}
 .Menu-list-item:hover .Mask, .Menu-list-item:active .Mask {
     color: #000;
     transform: skewX(12deg) translateX(5px);
}
 .Menu-list-item:hover .Mask + .Mask, .Menu-list-item:active .Mask + .Mask {
     transform: skewX(12deg) translateX(-5px);
}
 .Menu-list-item:hover::before, .Menu-list-item:active::before {
     transform: scale(1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
  <a class="btn-open-menu">
    <span class="hamburguer"><img src="https://upload.wikimedia.org/wikipedia/commons/b/b2/Hamburger_icon.svg"></span>
  </a>
  <div class="header-content">
    <a class="btn-close-menu"></a>
    <nav>
      <div class="Menu">
        <ul class="Menu-list" data-offset="10">
          <li class="Menu-list-item" data-offset="20" onclick="location.href='/home';">
            Home
            <span class="Mask"><span>Home</span></span>
            <span class="Mask"><span>Home</span></span>
          </li>
          <li class="Menu-list-item" data-offset="16" onclick="location.href='/about';">
            About
            <span class="Mask"><span>About</span></span>
            <span class="Mask"><span>About</span></span>
          </li>
          <li class="Menu-list-item" data-offset="12" onclick="location.href='/contact';">
            Contact
            <span class="Mask"><span>Contact</span></span>
            <span class="Mask"><span>Contact</span></span>
          </li>
        </ul>
      </div>
    </nav>
  </div>
  </header>

Upvotes: 0

user16435030
user16435030

Reputation:

You can add an event listener to the window itself so it closes anywhere you click.

window.addEventListener('click', (e) => {
  if (e.target !== document.getElementById('dropdown')) {
    // remove class here
  }
})

// (e.target as HTMLElement) if you're using typescript

Sometimes that can be problematic if you're clicking on an item inside the dropdown and it still closes because of the immediate element not being the dropdown itself. You can fix that using contains.

window.addEventListener('click', (e) => {
  const dropdown = document.getElementByid('dropdown')
  const item = document.getElementsByClass('dropdownItem')[0]

  if (e.target !== dropdown && !e.target.contains(item)) {
    // remove class here
  }
})

Upvotes: 1

Related Questions