3

I'm doing a menu and i need its child to have a large z-index so that it´s on top of a modal when this is opened. it works perfectly, but when i set the menu to 'position: fixed' and open the modal, the child is kept behind the modal. Here is the code, ignore the last part of the css, which is just animations. Thanks for the help.

const btn = document.querySelector('.btn'),
      overlay = document.querySelector('.menu-overlay'),
      menu = document.querySelector('.responsive'),
      close = document.querySelector('.close'),
      barTop = document.querySelector('#bar-one'),
      barMiddle = document.querySelector('#bar-two'),
      barBottom = document.querySelector('#bar-three');


btn.addEventListener('click', function(){
    overlay.classList.toggle('active');
    menu.classList.toggle('menuActive');
    barTop.classList.toggle('barTop');
    barMiddle.classList.toggle('barMiddle');
    barBottom.classList.toggle('barBottom');
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.menu-container {
  background: teal;
  padding: 10px 0;
  width: 100%;
  /* here is the issue i´m talking about */
  /* position: fixed; */
}

.menu {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 90%;
  margin: 0 auto;
}

.menu li {
  list-style: none;
  padding: 5px;
}

.menu li a {
  font-family: sans-serif;
  text-decoration: none;
  color: #fff;
}

.btn-container {
  z-index: 10000 !important;
}

.btn {
  text-decoration: none;
  display: flex;
  width: 22px;
  height: 18px;
  margin: 0 auto;
  flex-direction: column;
  justify-content: space-between;
}

.btn span {
  display: block;
  width: 100%;
  height: 2px;
  background: #fff;
  transition: all .3s;
}

.btn #bar-one.barTop {
  transform: translateY(8px) rotate(45deg);
}
.btn #bar-three.barBottom {
  transform: translateY(-8px) rotate(-45deg);
}
.btn #bar-two.barMiddle {
  opacity: 0;
}

.menu-overlay {
  position: fixed;
  width: 100%;
  top: 0;
  bottom: 0;
  background: rgba(0,0,0,.8);
  animation: fadeOverlay .3s linear;
  display: none;
  z-index: 99;
}
.menu-overlay.active {
  display: block;
}

@keyframes fadeOverlay {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 100%;
  }
}

.responsive {
  width: 100%;
  height: 100vh;
  position: fixed;
  top: 0;
  left: -100%;
  z-index: 100;
  transition: left .2s ease-in-out;
}

.responsive ul {
  display: flex;
  flex-direction: column;
  background: #000;
  width: 87%;
  height: 100%;
  padding: 20px;
}

.responsive ul li {
  padding: 5px;
}

.responsive ul li a {
  text-decoration: none;
  color: #fff;
}

.responsive.menuActive {
  left: 0;
}

.close {
  text-decoration: none;
  display: block;
  color: #fff;
  width: 10%;
  position: absolute;
  top: 0;
  right: 0;
  font-size: 40px;
  text-align: center;
  margin-top: 5px;
}

.close.closeActive {
  animation: fadeClose .4s linear;
}

@keyframes fadeClose {
  0%, 90% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Menu Celular</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <div class="menu-overlay"></div>
  <div class="menu-container">
    <ul class="menu">
      <li><a href="#">Home</a></li>
      <li class="btn-container">
        <a href="#" class="btn">
          <span id="bar-one"></span>
          <span id="bar-two"></span>
          <span id="bar-three"></span>
        </a>
      </li>
    </ul>
  </div>
  <div class="responsive">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Exit</a></li>
  </ul>
  </div>



<script src="./js.js" charset="utf-8"></script>
</body>
</html>
Santiago
  • 73
  • 1
  • 6
  • Possible duplicate of [z-index not working with fixed positioning](https://stackoverflow.com/questions/5218927/z-index-not-working-with-fixed-positioning) – Nick Mar 08 '19 at 18:51
  • I tried the solutions of that article but it doesn´to work in this case. I think because in that article there are two separate divs, while i´m working with parent-child. – Santiago Mar 08 '19 at 19:08

1 Answers1

2

position:fixed create a stacking context forcing all the element inside to be painted inside. Your issue is that now, the overlay is covering the menu container including all its element and setting a higher z-index to elements inside will do nothing. In your case it's the button container that you can no more move outside that stacking context.

You have to increase the z-index of the container

const btn = document.querySelector('.btn'),
      overlay = document.querySelector('.menu-overlay'),
      menu = document.querySelector('.responsive'),
      close = document.querySelector('.close'),
      barTop = document.querySelector('#bar-one'),
      barMiddle = document.querySelector('#bar-two'),
      barBottom = document.querySelector('#bar-three');


btn.addEventListener('click', function(){
    overlay.classList.toggle('active');
    menu.classList.toggle('menuActive');
    barTop.classList.toggle('barTop');
    barMiddle.classList.toggle('barMiddle');
    barBottom.classList.toggle('barBottom');
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.menu-container {
  background: teal;
  padding: 10px 0;
  width: 100%;
  /* here is the issue i´m talking about */
  position: fixed; 
  z-index:1000;
}

.menu {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 90%;
  margin: 0 auto;
}

.menu li {
  list-style: none;
  padding: 5px;
}

.menu li a {
  font-family: sans-serif;
  text-decoration: none;
  color: #fff;
}

.btn-container {
  z-index: 10000 !important;
}

.btn {
  text-decoration: none;
  display: flex;
  width: 22px;
  height: 18px;
  margin: 0 auto;
  flex-direction: column;
  justify-content: space-between;
}

.btn span {
  display: block;
  width: 100%;
  height: 2px;
  background: #fff;
  transition: all .3s;
}

.btn #bar-one.barTop {
  transform: translateY(8px) rotate(45deg);
}
.btn #bar-three.barBottom {
  transform: translateY(-8px) rotate(-45deg);
}
.btn #bar-two.barMiddle {
  opacity: 0;
}

.menu-overlay {
  position: fixed;
  width: 100%;
  top: 0;
  bottom: 0;
  background: rgba(0,0,0,.8);
  animation: fadeOverlay .3s linear;
  display: none;
  z-index: 99;
}
.menu-overlay.active {
  display: block;
}

@keyframes fadeOverlay {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 100%;
  }
}

.responsive {
  width: 100%;
  height: 100vh;
  position: fixed;
  top: 0;
  left: -100%;
  z-index: 100;
  transition: left .2s ease-in-out;
}

.responsive ul {
  display: flex;
  flex-direction: column;
  background: #000;
  width: 87%;
  height: 100%;
  padding: 20px;
}

.responsive ul li {
  padding: 5px;
}

.responsive ul li a {
  text-decoration: none;
  color: #fff;
}

.responsive.menuActive {
  left: 0;
}

.close {
  text-decoration: none;
  display: block;
  color: #fff;
  width: 10%;
  position: absolute;
  top: 0;
  right: 0;
  font-size: 40px;
  text-align: center;
  margin-top: 5px;
}

.close.closeActive {
  animation: fadeClose .4s linear;
}

@keyframes fadeClose {
  0%, 90% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Menu Celular</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <div class="menu-overlay"></div>
  <div class="menu-container">
    <ul class="menu">
      <li><a href="#">Home</a></li>
      <li class="btn-container">
        <a href="#" class="btn">
          <span id="bar-one"></span>
          <span id="bar-two"></span>
          <span id="bar-three"></span>
        </a>
      </li>
    </ul>
  </div>
  <div class="responsive">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Exit</a></li>
  </ul>
  </div>



<script src="./js.js" charset="utf-8"></script>
</body>
</html>

Doing this will make all the container to be above the overlay which is also not the needed result.

In case you want the overlay to behave as it was intially, your only way is to make it inside the position:fixed element and also move the responsive menu there, so you make all the elements to belong again to the same stacking context and you can adjust the z-index like you want

const btn = document.querySelector('.btn'),
      overlay = document.querySelector('.menu-overlay'),
      menu = document.querySelector('.responsive'),
      close = document.querySelector('.close'),
      barTop = document.querySelector('#bar-one'),
      barMiddle = document.querySelector('#bar-two'),
      barBottom = document.querySelector('#bar-three');


btn.addEventListener('click', function(){
    overlay.classList.toggle('active');
    menu.classList.toggle('menuActive');
    barTop.classList.toggle('barTop');
    barMiddle.classList.toggle('barMiddle');
    barBottom.classList.toggle('barBottom');
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.menu-container {
  background: teal;
  padding: 10px 0;
  width: 100%;
  /* here is the issue i´m talking about */
  position: fixed; 
}

.menu {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 90%;
  margin: 0 auto;
}

.menu li {
  list-style: none;
  padding: 5px;
}

.menu li a {
  font-family: sans-serif;
  text-decoration: none;
  color: #fff;
}

.btn-container {
  z-index: 10000 !important;
}

.btn {
  text-decoration: none;
  display: flex;
  width: 22px;
  height: 18px;
  margin: 0 auto;
  flex-direction: column;
  justify-content: space-between;
}

.btn span {
  display: block;
  width: 100%;
  height: 2px;
  background: #fff;
  transition: all .3s;
}

.btn #bar-one.barTop {
  transform: translateY(8px) rotate(45deg);
}
.btn #bar-three.barBottom {
  transform: translateY(-8px) rotate(-45deg);
}
.btn #bar-two.barMiddle {
  opacity: 0;
}

.menu-overlay {
  position: fixed;
  width: 100%;
  top: 0;
  bottom: 0;
  background: rgba(0,0,0,.8);
  animation: fadeOverlay .3s linear;
  display: none;
  z-index: 99;
}
.menu-overlay.active {
  display: block;
}

@keyframes fadeOverlay {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 100%;
  }
}

.responsive {
  width: 100%;
  height: 100vh;
  position: fixed;
  z-index:100;
  top: 0;
  left: -100%;
  z-index: 99;
  transition: left .2s ease-in-out;
}

.responsive ul {
  display: flex;
  flex-direction: column;
  background: #000;
  width: 87%;
  height: 100%;
  padding: 20px;
}

.responsive ul li {
  padding: 5px;
}

.responsive ul li a {
  text-decoration: none;
  color: #fff;
}

.responsive.menuActive {
  left: 0;
}

.close {
  text-decoration: none;
  display: block;
  color: #fff;
  width: 10%;
  position: absolute;
  top: 0;
  right: 0;
  font-size: 40px;
  text-align: center;
  margin-top: 5px;
}

.close.closeActive {
  animation: fadeClose .4s linear;
}

@keyframes fadeClose {
  0%, 90% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Menu Celular</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <div class="menu-container">
  <div class="menu-overlay"></div>
    <ul class="menu">
      <li><a href="#">Home</a></li>
      <li class="btn-container">
        <a href="#" class="btn">
          <span id="bar-one"></span>
          <span id="bar-two"></span>
          <span id="bar-three"></span>
        </a>
      </li>
    </ul>
  <div class="responsive">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Exit</a></li>
  </ul>
  </div>
  </div>



<script src="./js.js" charset="utf-8"></script>
</body>
</html>

If you cannot change the HTML, you have no chance to obtain what you want.


Related question to get more details about stacking context and painting order:

Why elements with z-index can never cover its child?

How to z-index a repositioned div in css?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415