2012-02-03

z-index not working?

This is the third time this month I've had this problem. I'm writing it down here in the hopes that it won't happen again.

Sometimes you want an element to overlap another element, but the structure of the document doesn't permit it. If you have this kind of setup:

Foo Content
Bar Content
<body>
<div id="foo">Foo Content</div>
<div id="bar">Bar Content</div>
</body>

#foo {
width: 100px;
height: 100px;
background-color: #009900;
}
#bar {
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background-color: #990000;
}

then bar will overlap foo, because it comes after it in the document.

This can be circumvented one of two ways - alter the structure of the document or alter the presentation of it. If you cannot alter the structure of the HTML, you can do it with Javascript:
window.onload = function () {

var foo = document.getElementById("foo");

//Appending an element removes it
// and places it back into the document,
// in this case *after* the bar div.
foo.parentNode.appendChild(foo);
}

Of course, this is kinda overkill when you can just alter the CSS using the z-index property:
#foo {
/* higher z-index means closer to the top */
z-index: 10;
}
#bar {
/* I never really trust z-indexes so I do multiples of 5 */
z-index: 5;
}

The only problem you might face is that none of this works if the element you want to be on top (foo in our case) has position: static. The solution? Change foo to position: relative.

Foo Content
Bar Content
#foo {
position: relative;
}

It makes perfect sense if you think about it. Elements default to position: static, meaning they come one after another. If you take one out of the flow by giving it position: absolute (or fixed or relative, for that matter), it will naturally be placed on top of that entire flow. You cannot then take something that is still part of that flow and make it be on top of the thing that is on top of it.

See, I knew it would be simple if I wrote it down.