Search code examples
javascripthtmlcssz-index

How to make link clickable when using z-index without turning all other elements z-index negative?


I'm trying to make a drop-down box with a button and a toolbar so that my drop-down will be behind the toolbar but in front of my main element. The problem is that to do this I use z-index with negative value because using positive value on the toolbar will cause it to get behind my drop-box due to positioning and hierarchy.

I know that if I'll go and change the z-index of elements in my DOM to smaller negative values (as suggested here) it will make my links clickable again, but this seems to be a very inefficient way of solving the issue. Plus, I'd rather not mess with the toolbar and break it different elements for each button as this can cause a lot of issues with responsiveness in the future. Please take a look at the JFiddler link below.

Here is my code:

$('#btn2').on('click', function() {
  console.log('Click!');
  var element = document.getElementById("sub-memu");
  element.classList.toggle("show");
})
body {
  background-color: gray;
  height: 100vh;
  padding: 0px;
  margin: 0px;
}

.toolbar {
  height: 40px;
  background-image: linear-gradient(white, red);
  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.35);
  position: relative;
}

.buttons {
  display: flex;
  flex-direction: row;
}

button {
  margin-right: 5px;
}

#sub-memu {
  position: absolute;
  display: flex;
  flex-direction: column;
  background-color: white;
  padding: 10px;
  min-width: 100px;
  z-index: -1;
  transform: translate(0px, -140%);
  transition: transform 1s;
}

main {
  padding: 10px;
  margin: 10px;
  background-color: yellow;
  height: calc(100% - 40px - 20px - 20px);
  position: relative;
  z-index: -2;
}

.show {
  transform: translate(0px, 25px) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <div class='toolbar'>
    <div class='buttons'>
      <button id='btn1'>
        Button 1
      </button>
      <div class='btn-wrapper'>
        <button id='btn2'>
          Button 2
        </button>
        <div id='sub-memu' class='subMenu'>
          <a href='#'>Can you click me?</a>
          <a href='#'>Can you click me?</a>
          <a href='#'>Can you click me?</a>
          <a href='#'>Can you click me?</a>
        </div>
      </div>
    </div>
  </div>
  <main>
    This is my main element.
    <a href="#">You should be able to click me</a>.
  </main>
</body>

https://jsfiddle.net/atb8yq6e/1/

What I'm trying to achieve is the same behavior as can bee seen in my JSFiddle link (drop-down box lowering from behind the navigation bar but in front of my main content) but with active links, without going through my DOM tree and changing every overlapping element's z-index to lower number.

Thank you all in advance, Lior.


Solution

  • Add z-index to body element to make sure you create a stacking context and avoid having the element going behind it:

    $('#btn2').on('click', function() {
      console.log('Click!');
      var element = document.getElementById("sub-memu");
      element.classList.toggle("show");
    })
    body {
      background-color: gray;
      height: 100vh;
      padding: 0px;
      margin: 0px;
      position:relative;
      z-index: 0;
    }
    
    .toolbar {
      height: 40px;
      background-image: linear-gradient(white, red);
      box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.35);
      position: relative;
    }
    
    .buttons {
      display: flex;
      flex-direction: row;
    }
    
    button {
      margin-right: 5px;
    }
    
    #sub-memu {
      position: absolute;
      display: flex;
      flex-direction: column;
      background-color: white;
      padding: 10px;
      min-width: 100px;
      z-index: -1;
      transform: translate(0px, -140%);
      transition: transform 1s;
    }
    
    main {
      padding: 10px;
      margin: 10px;
      background-color: yellow;
      height: calc(100% - 40px - 20px - 20px);
      position: relative;
      z-index: -2;
    }
    
    .show {
      transform: translate(0px, 25px) !important;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <body>
      <div class='toolbar'>
        <div class='buttons'>
          <button id='btn1'>
            Button 1
          </button>
          <div class='btn-wrapper'>
            <button id='btn2'>
              Button 2
            </button>
            <div id='sub-memu' class='subMenu'>
              <a href='#'>Can you click me?</a>
              <a href='#'>Can you click me?</a>
              <a href='#'>Can you click me?</a>
              <a href='#'>Can you click me?</a>
            </div>
          </div>
        </div>
      </div>
      <main>
        This is my main element.
        <a href="#">You should be able to click me</a>.
      </main>
    </body>

    Related: Why can't an element with a z-index value cover its child?