Hide overflow behind stacked div with transparent background on top of body with SVG background

Viewed 2037

I have a layout that contains a fixed div (#navigation) that has buttons. The layout also includes scrollable content (.card).

#navigation currently has a green background for demo purposes. Like so:

#navigation {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translate(-50%, 0%);
  background: green;
  padding: 25px;
}
<div id="navigation"><button id="btn1">Button</button>
  <button id="btn2">Button</button>
  <button id="btn3">Button</button>
  <button id="btn4">Button</button>
</div>

I would like to hide the any part of any .card element as soon as it goes behind the green background. So, I use z-index stacking order and it works well. Like so:

#card-wrapper {
  width: 250px;
  margin: 100px auto;
}

.card {
  height: 200px;
  width: 200px;
  background: #131418;
  margin: 1em auto;
  display: inline-block
}

#navigation {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translate(-50%, 0%);
  z-index: 1;
  background: green;
  padding: 25px;
}

#main {
  text-align: center;
}
<div id="main">

  <div id="navigation"><button id="btn1">Button</button>
    <button id="btn2">Button</button>
    <button id="btn3">Button</button>
    <button id="btn4">Button</button>
  </div>

  <div id="card-wrapper">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
  </div>

</div>

However, I would also like not to use the green background in production. This means that #navigation should not have a background and only the buttons inside should be visible.

So my question is how do I hide the top-side overflow from #card-wrapper as soon as it reaches the hypothetical green background?

#card-wrapper {
  width: 250px;
  margin: 100px auto;
}

.card {
  height: 200px;
  width: 200px;
  background: #131418;
  margin: 1em auto;
  display: inline-block
}

#navigation {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translate(-50%, 0%);
  z-index: 1;
  padding: 25px;
  border: 1px solid;
  background: transparent
}

#main {
  text-align: center;
}

body {
  margin: 0 auto;
  background: url(http://svgur.com/i/42T.svg);
  background-attachment:fixed;
  background-size:cover;
}
<div id="main">

  <div id="navigation"><button id="btn1">Button</button>
    <button id="btn2">Button</button>
    <button id="btn3">Button</button>
    <button id="btn4">Button</button>
  </div>

  <div id="card-wrapper">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
  </div>

</div>

Note, the body element has an SVG background, I cannot add any background to #navigation as it would look bad.

I am open to all solutions CSS/JS/jQuery as long as they do not involve hard-coded values

6 Answers

Try to set same background for #navigation also, with same background-position (see example below)

#card-wrapper {
  width: 250px;
  margin: 100px auto;
}

.card {
  height: 200px;
  width: 200px;
  background: #131418;
  margin: 1em auto;
  display: inline-block
}

#navigation {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1;
  padding: 40px 25px 25px 25px;
  background: #ffffff url(http://svgur.com/i/42T.svg);
  background-attachment: fixed;
  background-size: cover;
  background-position: 0 0;
}

#main {
  text-align: center;
}

body {
  margin: 0 auto;
  background: #ffffff url(http://svgur.com/i/42T.svg);
  background-attachment: fixed;
  background-size: cover;
  background-position: 0 0;
}
<div id="main">

  <div id="navigation">
    <button id="btn1">Button</button>
    <button id="btn2">Button</button>
    <button id="btn3">Button</button>
    <button id="btn4">Button</button>
  </div>

  <div id="card-wrapper">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
  </div>

</div>

If you don't mind to have fixed value for the height of the buttons - then your task can be solved through background-clip style. In example below I've also added click handlers for cards and buttons to demonstrate that cards are still clickable.

$('.card').on('click',function(){
  $(this).addClass('clicked');
})
$('button').on('click',function(){
  $('.card').removeClass('clicked');
})
#card-wrapper {
  width: 250px;
  margin: 100px auto;
}

.card {
  height: 200px;
  width: 200px;
  background: #131418;
  margin: 1em auto;
  display: inline-block
}

#navigation {
  background-image: url(http://svgur.com/i/42T.svg);
  background-attachment: fixed;
  background-size: cover;
  background-clip: content-box;
  border: 0 none;
  padding: 0;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  position: fixed;
  z-index: 1;
  box-sizing: border-box;
/**
calc() calculation values:
 25px - .buttons-list padding  
 20px - top offset of #navigation (it is also padding-top value)
 30px - button height;
*/
  padding: 20px 0 calc(100vh - 25px * 2 - 20px - 30px);
  pointer-events: none;
}

button {
  height: 30px
}

#main {
  text-align: center;
}

body {
  margin: 0 auto;
  background: url(http://svgur.com/i/42T.svg);
  background-attachment:fixed;
  background-size:cover;
}

.buttons-list {
  padding: 25px;
  pointer-events: initial;
}

/* Just for click events demonstration */
.card.clicked{
  background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">

  <div id="navigation">
    <div class="buttons-list">
      <button id="btn1">Button</button>
      <button id="btn2">Button</button>
      <button id="btn3">Button</button>
      <button id="btn4">Button</button>
    </div>
  </div>

  <div id="card-wrapper">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
  </div>

</div>

Related