August 15th, 2007 - by Paul OB

No I don’t want you to take a nap. I’d rather you took a little tour with me and explore the possibilities that the CSS z-index property has to offer. In a previous article I briefly touched on how to use z-index and thought now was the time to expand more on the subject. So wake yourself up, get your thinking caps on and follow me as we come to grips with z-index.

Try and hang with me during the technical side of things because we have a fun Lose Weight Exercise at the end!

Above or Below

The CSS z-index property is a mechanism for defining the stacking level of positioned elements within a document. It allows elements to be moved above or below other elements on a page along an imaginary line that extends from inside the monitor towards the viewer. The lower the z-index the further away the element will appear in the stacking context and conversely a higher z-index brings the element closer to the viewer. As often is the case, there are rules to follow and reasons why some things can’t be moved which we will look at in this article.

Most of the time when laying elements on a page you don’t really need to consider their stacking order because the elements don’t actually overlap in the normal flow of the document. It’s only when you start positioning elements so that overlapping occurs that you need to consider which element should be on top and which element should be underneath. Elements can be positioned using absolute, relative or fixed positioning or even shifted on top of each other using negative margins.

Only positioned elements can have z-index

You can’t just apply z-index to any element — only positioned elements can have z-index applied. This means that if you want to place one element on top of another you first have to make it a positioned element and then you can control the stacking order by manipulating the z-index. Therefore, if an absolutely positioned element overlaps your static container you can apply position:relative to your static container and then apply a higher z-index to bring it on top of the absolutely positioned element (this does depend on the stacking context of the elements concerned and will be discussed further down the page). By applying position:relative to the static container (without specifying co-ordinates) you are making that element a positioned element, but more importantly you are not interfering with the document flow in anyway or changing how that element behaves.

Another byproduct of adding position:relative to an element is that the element now becomes the “containing block” for further positioned elements. This would allow you to define absolutely placed elements in relation to that newly created stacking context. The “containing block” of an element is defined as the nearest ancestor that has a value set for the property “position” other than static (e.g. the parent should be position:relative or position:absolute or position:fixed). If no parent exists then the containing block becomes the root element which is the HTML (or body outside of margins set), which effectively means the viewport.

However, adding position relative will not automatically create a new stacking context where z-index is concerned as a positioned element will default to z-index:auto which effectively means that it does not create a new stacking context. However, IE gets this wrong and instead all positioned elements get z-index:0 applied which causes a local stacking context for its child elements.

Usually this would be what you want, but it does cause problems with browser compatibility unless you understand and cater for it. The bug is documented here and as long as you remember that in IE any positioned element establishes a new stacking context then the bug won’t bite you very often.

Enough of the jargon for now, let’s look at a simple example to ease you in gently. Consider the following code:

  1. .parent1{
  2. position:absolute;
  3. top:100px;
  4. left:100px;
  5. width:300px;
  6. height:200px;
  7. background:aqua;
  8. }
  9. .child{
  10. background:yellow;
  11. position:relative;
  12. height:40px;
  13. width:200px;
  14. margin:20px 0 0 10px;
  15. }
  16. .two{margin:-25px 0 0 20px;background:green}
  17. .three{margin:-25px 0 0 30px;background:red;}
  1. <div class="parent1">
  2. <p>Parent</p>
  3. <div class="child one">
  4. <p>Child one</p>
  5. </div>
  6. <div class="child two">
  7. <p>Child 2</p>
  8. </div>
  9. <div class="child three">
  10. <p>Child 3</p>
  11. </div>
  12. </div>

Running the above code will give you the result shown in Figure 1 below:

Figure 1

Although there are no z-indexes specified in the above code we still get the overlapping effect we desired. This is because the parent gets an automatic z-index of auto (zero for IE) and the children will take on the parents z-index level if nothing else has been defined. This means that our children all have the same z-index as each other and in that case the browser will stack them according to how they are rendered from the document tree so that elements later in the HTML will get priority over those earlier in the document (although this isn’t explicitly defined in the specs so you could get variances in some browsers). You may find however that as situations get more complex and you want overlapping to be certain then you should define the level manually so that you can force the issue and not leave anything to chance.

It is worth pointing out that negative values for z-indexes are allowed, but are treated differently by various browsers so it’s best not to use them at all and there is rarely a need to use them anyway. For example, in Firefox 2 adding a negative z-index to child 3 in the example above would move it behind the parent (which has z-index:0) and effectively makes the child disappear. IE and Opera on the other hand would move child 3 behind child 1 and 2 but not behind the parent. This effectively means that negative z-indexes are too unreliable to use in a real world application.

Referring back to Figure 1 — assuming that we want to move child 1 in front of children 2 and 3 we could simply add the following code:

  1. .one{z-index:2}

The result is that child 1 now moves in front of the other children as demonstrated in Figure 2 below.

Figure 2

Of course things are never as simple as that — the fact that an element has a higher z-index than something else doesn’t always mean it will be on top of elements with a lower z-index. The determining factor depends on the z-index level of the containing block of that element (which will be the nearest ancestor with a position defined as explained above). It is the z-index of the main parent containing block that ultimately dictates whether its children will overlap other elements on the page and the containing block’s z-index would need to be higher than the z-index of the other elements containing block.

This means that you cannot interweave the children of separate containing blocks. The children will either all be on top or all be underneath. Sometimes you may want them to overlap, but this is just not possible unless all children live in the same house (i.e all have the same parent as their stacking context).

We can demonstrate this effect with another short example:

  1. *{margin:0;padding:0}
  2. .parent{
  3. position:absolute;
  4. top:100px;
  5. left:100px;
  6. width:300px;
  7. height:200px;
  8. background:aqua;
  9. }
  10. .child{
  11. background:yellow;
  12. position:relative;
  13. height:40px;
  14. width:200px;
  15. margin:20px 0 0 10px;
  16. }
  17. .p1{z-index:1;margin-top:5px}
  18. .p2{z-index:2;left:250px;background:green}
  19. .one {z-index:999;}
  20. .two{z-index:0;background:red;margin:45px 0 0 -50px}
  1. <div class="parent p1">
  2. <p>Parent One - z-index:1</p>
  3. <div class="child one">
  4. <p>Child 1 - z-index 999</p>
  5. </div>
  6. </div>
  7. <div class="parent p2">
  8. <p>Parent Two - z-index:2</p>
  9. <div class="child two">
  10. <p>Child 2- z-index:0</p>
  11. </div>
  12. </div>

The above code creates two parent elements each with their own child. Parent 1 has a z-index of 1 and parent 2 has a z-index of 2. We then give parent 1’s’ child a z-index of 999 and parent 2’s child a z-index of 0. You will see from Figure 3 that although parent 1’s child has a z-index of 999 it is still underneath parent 2’s child which only has a z-index of zero.

Figure 3

You need to think of each parent as the main container so you can disregard any z-index’s on the children because ultimately it’s the parents z-index that dictates which element will be on top. The z-index of the children is only useful for organizing the children within that block. This effectively means that you cannot interweave the children of these two blocks as either they will all be on top or they will all be underneath. To create an interweave effect the elements would have to be separate and not contained by a parent or contained by the same parent such as the initial containing block (viewport).

In complicated layouts, such as drop down flyout menus, then z-indexing can become a headache due to the variance in browser handling but if you read and understand the above rules then that will help you to understand what’s going on and how to address the issues.

Z-index Rollover

Now that you know a bit about z-index let’s try it out in a more practical way. To finish this article we will create a image gallery rollover effect purely by manipulating the z-index of the images alone. The basics are simple — we will stack a number of images on top of each other and give them all the same z-index. The images will be slightly offset so that you can select each one by hovering over each image. When hovered over we will simply raise its z-index higher than those of its neighbors. This will have the effect of bringing the image to the front of the stack and making it all visible.

Here’s the code:

  1. ul.z{
  2. list-style:none;
  3. margin:40px;
  4. padding:0;
  5. position:relative;
  6. width:100%;
  7. }
  8. .z li{
  9. float:left;
  10. margin:10px 0 0 -260px;
  11. }
  12. .z{margin:0}
  13. .z li.two{margin-top:20px}
  14. .z li.three{margin-top:40px}
  15. .z li.four{margin-top:60px}
  16. .z li.five{margin-top:80px}
  17. .z li.six{margin-top:100px}
  18. .z{margin-top:120px}
  19. .z img {
  20. padding:2px;
  21. border:1px solid #000;
  22. background:#fff;
  23. display:block;
  24. }
  25. .z a img{position:relative;z-index:1}
  26. .z a:hover{visibility:visible;}/* ie needs this*/
  27. .z a:hover img{z-index:2;}
  1. <h1>Z-index Demonstration</h1>
  2. <p>When you hover over an image its z-index is increased and that brings it to the front of the stack.</p>
  3. <ul class="z">
  4. <li class="one"><a href="#"><img src="images/zimg1.jpg" alt="Z-index test 1" width="300" height="300" /></a></li>
  5. <li class="two"><a href="#"><img src="images/zimg2.jpg" alt="Z-index test 2" width="300" height="300" /></a></li>
  6. <li class="three"><a href="#"><img src="images/zimg3.jpg" alt="Z-index test 3" width="300" height="300" /></a></li>
  7. <li class="four"><a href="#"><img src="images/zimg4.jpg" alt="Z-index test 4" width="300" height="300" /></a></li>
  8. <li class="five"><a href="#"><img src="images/zimg5.jpg" alt="Z-index test 5" width="300" height="300" /></a></li>
  9. <li class="six"><a href="#"><img src="images/zimg6.jpg" alt="Z-index test 6" width="300" height="300" /></a></li>
  10. <li class="seven"><a href="#"><img src="images/zimg7.jpg" alt="Z-index test 7" width="300" height="300" /></a></li>
  11. </ul>

Running the above code will give you the layout shown in Figure 4:

Figure 4

Then when you mouse over an image you will get the effect shown in Figure 5:

Figure 5

As you can see the image being hovered (indicated by the arrow) comes to the front of the stack and creates a nice little viewing gallery.

The code is surprisingly simple; the magic is performed in three lines of code here:

  1. .z a img{position:relative;z-index:1}
  2. .z a:hover{visibility:visible;}/* ie needs this*/
  3. .z a:hover img{z-index:2;}

The images are all position:relative and set to z-index 1. On hover the z-index is raised to 2 making it appear on top of everything else. To get this to work in IE you will need to add the following code:

  1. .z a:hover{visibility:visible;}/* ie needs this*/

IE will only action any change of state on an image when something changes on the anchor itself. You could make a background colour change and this would work, but the visibility:visible method works all the time without affecting the anchors appearance; therefore it’s the perfect choice for this as there are no drawbacks to it.

That’s basically all there is to the demo and for a small amount of code it produces a reasonable effect and you can see the live demo here.

To finish the article I should re-iterate that in very complicated situations there are bugs exhibited by various browsers (especially IE) with z-index and we have not delved into really complex situations here. The process of making things work is first to understand how they should work and then later discover why it’s not working and find work-a-rounds for those cases.

For now I’ll leave you to experiment with the above and perhaps we will revisit this at a later date with some of the more complex issues and bugs to look at. It’s getting late now anyway and I need to catch up on my z’s zzzzzzzzzzzz…..

32 Responses to “Give Me Some Zzzzz’s”

1 Paul OB

I should clarify again that setting a parent to position:relative (or absolute etc) doesn’t automatically create a local stacking context. It’s only when you also add a z-index (other than auto) that it creates the local stacking context. However IE gets this wrong and always creates a stacking context as soon as you position an element.

Adding position relative (or absolute etc) to an element does however create a containing block for further positioned elements so that you can place them in relation to this parent.

I just thought it worth mentioning again as I have referred to the containing block a couple of times in the article but was also assuming that z-index had been set.

2 Patrick Burt

Great article, I especially liked the image example for useful real-life application of the theory.

3 Golgotha

I like that image gallery rollover effect too! Nice work Paul!

4 Jen / domestika

This is going to take some studying for me to get my head around, but I’m grateful for this comprehensive article – I was googling in hopes of such a thing just this afternoon, but ended up having to compromise on the image/text arrangement I originally had in mind. Thanks much for this.

5 hdoug

very good! thanks for the lesson!

6 Enrique

Mil gracias por lo claro y conciso del artículo.

7 annex

I’m curious about using z-index in combination with a flash object. On my art site, I have a flash slideshow and a css driven dropdown menu. No matter how I tweaked the z-index and transparency settings of these elements, I could not get the menu to go OVER the flash across the different browsers…
Any ideas?

8 ses5909

This is awesome Paul. You truly are a genius!

9 Golgotha

@annex: try this – <param name=”wmode” value=”opaque” /> use opaque instead of transparent.

10 Darren

Wow great example. I had never thought of that. Great way to demonstrate the z-index

11 Paul OB

@annex – Mark was almost correct but you also need to add this to the embed tag also for firefox:




12 Golgotha

Good call Paul.

I use the SWFObject so I always forget about the old way.

If you’re using Flash and not using the SWFObject you may want to look into it.

13 Laura

Really useful, thanks

14 Best of August 2007 | Best of the Month

[…] Give Me Some Zzzzz’s An extensive article about the z-index-property in CSS for stacking div-layers upon each other. Important: only absolutely or relatively positioned elements can have z-index. […]

15 lost node » Blog Archive » Best of August 2007

[…] Give Me Some Zzzzz’s An extensive article about the z-index-property in CSS for stacking div-layers upon each other. Important: only absolutely or relatively positioned elements can have z-index. […]

16 » Best of August 2007

[…] Give Me Some Zzzzz’s An extensive article about the z-index-property in CSS for stacking div-layers upon each other. Important: only absolutely or relatively positioned elements can have z-index. […]

17 Berater

fine lesson, super work

18 vavalen

a lot of knowleage to sudy,thankyou

19 My-Ad-Sense

[…] Give Me Some Zzzzz’s An extensive article about the z-index-property in CSS for stacking div-layers upon each other. Important: only absolutely or relatively positioned elements can have z-index. […]

20 Affordable Insurance

This is awesome! I was noticing a while back that if I right click on an object in my web design program that I can send items to either front or back using layers (like a deck of cards placed on its side I guess) and I noticed that from an SEO standpoint, that the items also moved inside of the HTML. Items that were moved towards the back would appear first in the code after the . I started using this approach for setting the main text with my keywords towards the top of the page in the html. Even if that paragraph appeared at the bottom of the page, the search engines would see it first!

I had noticed this and asked someone else if this is either a function that could be done with css or if they could explain it to me. This explanation of how to do the same thing with css is superb!



21 Michael Hendrickx

Wonderful article, very nice!

22 Naysan

Wow, this was just the kind of thing I was trying to find. Thanks!

Is it possible to separate the element being hovered and the element with the modified z-index? So, instead of rolling over the images themselves, you roll over a list naming the pictures, and the named picture gets bumped?
I’m new to CSS, so I don’t know if it’s possible to do this entirely in CSS, but any help would be awesome.

23 DaRedMonkey

I am trying to get a picture to be on top of this flash app but not successful.

Here’s what I did any advice is appreciated.

…object codes here…

24 abel

great article!
I look for some information about layer positionning in which one of them is a script that are calling a string of images; the second is another layer that is transparent and it’s a buton,
i apply positions as well, but it doesn’t work, any idea? thanks

25 Paul OB

Hi abel,

You will need to post a link to the problem as each situation is different and there can be many factors involved. (If you can’t post a link the visit the Sitepoint css forums and post snippets of your code and someone will help).

Ultimately its the parent of each element that will control its stacking level and you may be addressing the wrong element.

If you have applied position:relative and a z-index to each element and they still don’t overlap as you want then move back up the tree to the parents of each and set a position a z-index as required.

[…] to see a z-index paper (Give Me Some Zzzzz’s), also some people have asked this question (see below message for Flash will see), it is to Flash […]


Your article is awesome. I wish it could fix my problem in IE. I’ve been searched online and have tried to make z-index work. I even add this code to my functions.php:

<?php add_filter('the_content', 'add_opaque_to_all_flash'); function add_opaque_to_all_flash($string) { $string = str_ireplace('<embed type="application/x-shockwave-flash"', '

Nothing works for me. Very frustrate.

28 Paul OB

Hi Lanna,

Flash is always awkward and you need to add the wmode parameters to the param tag and the embed tag.

You still need to layer the rest of the elements accordingly and remember its ultimately the positioned parent that controls the stacking context for elements outside the current context.

29 Paul OB

@Lanna: Hmm I forgot code gets stripped out. Take a look at replies 9 and 11 as they contain the same information.


Thanks Paul for your reply. I have this code for my Carousel:

Little Tikes Outdoor Toys For Sale: var amzn_wdgt= { width:”935″, height:”200″, title:”Best Selling in Little Tikes Outdoor Toys”, widgetType:”Bestsellers”, searchIndex:”Toys”, browseNode:”711761011″, shuffleProducts:”True”, showBorder:”True”, marketPlace:”US”, tag:”onsttost-20″, widget:”Carousel” };

How can I add the wmode parameters to the param tag and the embed tag? I doubt this code will be stripped out again.

31 Paul OB

Hi Lanna,

You should post in the Sitepoint forums as its too awkward to bug hunt through a blog.

I’m guessing that you need to provide the parameter through the widget type variable but flash embedding is outside of my knowledge I’m afraid.



Ok Paul I’ll head over to the link that you’ve provided. Thanks again.

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators

Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

You need to download the Flash player from Adobe

Other Sites