Monday, March 19, 2012

IE7's z-index or why do things appear behind others?

Again with coding a website; in this instance it should be simple - a list of names; using the technique to automatically set onmouseover to elements by class when the name is hovered over with the cursor a pop-up appears next to it with some additional information.It works in IE7, Opera, Firefox and Chrome.

Rather than have just one long list I then columnised it by splitting it into three div elements and using the inline-block and IE7 inline fix to get it to display in all the major browsers... except the popup doesn't work correctly in just one browser - can you guess which?

No prizes if you said IE7. However the reason it doesn't work is interesting in and of itself and displays just how messed up IE7 really is/was.

It's all to do with stacking and the z-index; for those going "Huh?" Think of every element as a piece of paper that is laid on top of the other in the order that the code reads them; z-index can alter the order. Where confusion can lie is that there may be multiple stacks of papers. for example starting with the body element that normally forms the lowest item in a stack if I add a couple of div elements they should appear over the body element

<div id="1"></div>
<div id="2"></div>

So the body element has an effective z-index of 0 and the two div elements an effective z-index of 1. But what happens if I position either the first of second div so they overlap each other? Draw order determines overlap in this case div 2 will appear above div 1. Again imagine them as sheets of paper div 1 goes down first and then div 2.

Let's add another couple as part of the main div elements:

<div id="1"><div id="1-1"></div></div>
<div id="2"><div id="2-1"></div></div>

How does div 1-1 appear? It's considered to be in the same stack as div 1. So again with the paper analogy div 1 is placed; then div 1-1; then div 2 overlapping both and div 2-1 on top. Where things get confusing is when a z-index is applied.

If I set a z-index of 100 to div 1-1 one might expect it to appear on the top and be surprised when it doesn't; this is because the number is relative to the stack. In this case we have two stacks and div 1-1 is part of the first as such it will always be below div 2 and its contents as they form a second stack.

The way around this is to set the z-index of the stack itself; that is the first element that makes it up. If I set div 1 to a z-index of 5 for example it will appear above div 2 and div 2-1 and, logically enough, div 1-1 will also appear above that.

How does that work with my three columns and the popup? Well what I would expect is that the first column is drawn first and appears lowest and the popup is part of that stack; thus it appears beneath the second column and so on.

However knowing this I gave the popup a position of "absolute". Beyond its positioning this has the effect of making that element into its own stack.

Despite draw order determining overlap all three columns share an actual z-index of 0. Set the popup itself to have a z-index of 1 and all the 0 z-indexed columns are drawn first in order and the pop-up should appear last on top of them all. Sorted.

Except not in IE7. The popup still appears beneath the next column. While trying to solve this my experimentation led to some oddness. To test I gave the popup a background colour of white and the columns yellow this is how they stacked:

Yellow background of column
White background of popup
Popup Text
Column Text

However change the column to a position of "relative" and the stacking becomes:

White background of popup
Popup Text
Yellow background of column
Column Text

Which is what I'd have expected in the first place. Setting a position to an element, even one that doesn't take it out of the stack, seems to reset the stacking order in IE7. How to fix it?

Well back to the basics. IE7 is treating my popup as being part of the column's stack even though it shouldn't so anything I do with that will be relative to that stack's z-index; so I need to change the stack itself. In this case I use the * hack to add some code that only IE7 will pick up and I set the z-index of my first column to 3; my second to 2 and my third to 1; I then keep my popup set to 1 and the columns with a position of relative to stabilise the stacks.

.column {position:relative;}
.column1 {*z-index:3;}
.column2 {*z-index:2;}
.column3 {*z-index:1;}
.popup {z-index:1; position: absolute;}

Back to the paper analogy and this time I'm given the three stacks of paper in column order but instructions on them tell me to put them down in reverse order. The popup appears 1 place above its respective column/stack which means it's always above those that were placed before it.



Anonymous said...

How clever is that!
thx!!! solved my problem!