Peter Kottas
Peter Kottas

Reputation: 943

Fixed header&sidebar z-index issue

it's been a while! I am currently trying to solve a problem and I was hoping somebody could help me out. I have a fixed sidebar and a header. Both cast dropshadow. However, I don't want the header to cast shadow on the sidebar (I want them to be on the same level). At the same time, header contains drop-downs and these need to hover over everything. Since it's rather complex, I've created a jsfiddle.

Simple example

I've been forced to paste the code here as well for some reason (SO input validation).

<div class="layout">
  <div class="header z-depth-2">
    <div class="dropdown-toogle">
      <div class="dropdown-menu">
      </div>
    </div>
  </div>
  <div class="page-wrapper">
    <div class="sidebar z-depth-2">
    </div>
    <div class="content">
    </div>
  </div>
</div>

And css

.layout {
  width: 100%;
  height: 100%;
  position: relative;
}

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 70px;
  background-color: blue;
  z-index: 101;
}

.sidebar {
  position: fixed;
  top: 70px;
  left: 0;
  width: 200px;
  background-color: green;
  bottom: 0;
  z-index:101;
}

.content {
  padding-left: 200px;
  width: 100%;
  height: 100%;
}

.page-wrapper {
  padding-top: 70px;
  height: 100%;
}

.dropdown-toogle {
  margin-right: 100px;
  float: right;
  position: relative;
  height: 100%;
  width: 50px;
  background-color: yellow;
}

.dropdown-menu {
  position: absolute;
  top: 100%;
  right: 0;
  width: 400px;
  height: 200px;
  background-color: grey;
  z-index:1000;
}

.z-depth-2 {
  box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
}

Notice how when you change view-port width, drop-down slides behind sidebar even when it's z-index is greater.

If I increase z-index of header, it starts casting shadow on the sidebar (drop-down starts working) which I want to avoid. I've been playing with different combination but was unable to sort it out properly.

Hope I managed to make it clear, help much appreciated!

Upvotes: 1

Views: 1584

Answers (2)

Peter Kottas
Peter Kottas

Reputation: 943

First of all, big thanks goes to Don, his approach is totally valid, clever and possibly even better than what I used. However I figured I'll post my final solution as well as somebody might value having 2 approaches. All I did is I've added a "fake" gradient absolutely positioned bellow the header and to the right of sidebar. The reason why I've done so is basically I used technologies that I know and can rely on. I didn't like the overflow auto on the content as well. Anyways, this is it:

https://jsfiddle.net/79gykeu3/11/

<div class="layout">
    <div class="header">
        <div class="header__shadow">
        </div>
        <div class="dropdown-toogle">
            <div class="dropdown-menu">
            </div>
        </div>
    </div>
    <div class="page-wrapper">
        <div class="sidebar">
            <div class="sidebar__shadow">
            </div>
        </div>
        <div class="content">
        </div>
    </div>
</div>

Css

.layout {
    width: 100 %;
    height: 100 %;
    position: relative;
}

.header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 70px;
    background - color: blue;
    z - index: 103;
}

.sidebar {
    position: fixed;
    top: 70px;
    left: 0;
    width: 200px;
    background - color: green;
    bottom: 0;
    z - index:101;
}

.content {
    padding - left: 200px;
    height: 8000px;
}

.page - wrapper {
    padding - top: 70px;
    height: 100 %;
}

.dropdown - toogle {
    margin - right: 100px;
    float: right;
    position: relative;
    height: 100 %;
    width: 50px;
    background - color: yellow;
}

.dropdown - menu {
    position: absolute;
    top: 100 %;
    right: 0;
    width: 400px;
    height: 200px;
    background - color: grey;
    z - index:1000;
}

.header__shadow {
    position: absolute;
    height: 7px;
    left: 200px;
    right: 0;
    top: 100 %;
    background: linear - gradient(to bottom, rgba(0, 0, 0, 0.35) 0%,rgba(0, 0, 0, 0) 100%);
}

.sidebar__shadow {
    position: absolute;
    left: 100 %;
    top: 0;
    bottom: 0;
    width: 7px;
    background: linear - gradient(to right, rgba(0, 0, 0, 0.35) 0%,rgba(0, 0, 0, 0) 100%);
}

Upvotes: 0

Don
Don

Reputation: 4157

With your current layout this isn't possible. Since the header is set to a z-index behind the sidebar essentially any child of the header will also be behind the sidebar. (Read more on stacking contexts)

In order to solve this issue what you can do is use an inset box-shadow on the content pane. This will make it so there is a shadow as if it's being cast by the header and sidebar but it's really the container casting it on itself. This way you don't need to worry about the header casting onto the sidebar and the sidebar can safely sit "behind" the header. With this you don't need to fiddle with z-index at all (though I didn't remove them in case it's needed for other things on the page).

In order to get this to work properly I had to change the padding you were using to position the content element with margin but honestly this is a better property to use for adding space around an element. I recommend you also read up a bit on when to use padding vs margin.

https://jsfiddle.net/79gykeu3/6/

HTML

<div class="layout">
  <div class="header z-depth-2">
    <div class="dropdown-toogle">
      <div class="dropdown-menu">
      </div>
    </div>
  </div>
  <div class="page-wrapper">
    <div class="sidebar z-depth-2">
    </div>
    <div class="content">
    </div>
  </div>
</div>

CSS

The thing to note is the .content class now has the box-shadow

html {
  height: 100%;
}

body {
  width: 100%;
  height: 100%;
  margin: 0;
}

.layout {
  width: 100%;
  height: 100%;
  position: relative;
}

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 70px;
  background-color: blue;
  z-index: 103;
}

.sidebar {
  position: fixed;
  top: 70px;
  left: 0;
  width: 200px;
  background-color: green;
  bottom: 0;
  z-index:101;
}

.content {
  margin-left: 200px;
  width: 100%;
  height: 100%;
    box-shadow: inset 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
}

.page-wrapper {
  margin-top: 70px;
  height: 100%;
}

.dropdown-toogle {
  margin-right: 100px;
  float: right;
  position: relative;
  height: 100%;
  width: 50px;
  background-color: yellow;
}

.dropdown-menu {
  position: absolute;
  top: 100%;
  right: 0;
  width: 70%;
  height: 200px;
  background-color: grey;
  z-index:1000;
}

.z-depth-2 {
}

Upvotes: 2

Related Questions