A Detailed Look at the z-index CSS Property

Z-Index PropertyMost CSS properties that a web developer deals with regularly are instantaneous in their application to elements on the page. For example, when you add the background-color or font-size property to an element on your page, in most cases you will see the results immediately upon page refresh. But other CSS properties are not quite as “plug and play” as we would like.

The z-index property is one example of the latter. I would venture to guess that z-index is probably the CSS property that is more speedily abandoned than any other. Very often — when I previously didn’t understand z-index — I would try to apply it to an element, hoping that the element would automatically “jump” to the top in the page’s stacking order. But that didn’t happen, so I would abandon that method and try some other way to solve the problem. Maybe you’ve had the same experience. Hopefully this article will clear up some misunderstandings regarding z-index.

What Exactly Does It Do?

Basically, the z-index property sets the stack order of an element. An element with greater stack order is always in front of another element with lower stack order. That over-simplified definition is exactly why beginning CSS developers often use z-index incorrectly.

The natural stacking order of a web page’s elements is decided by the order in which the elements appear in the page’s markup. Let’s provide a simple example that we can use to explain stacking order and how z-index can be used correctly (and incorrectly):

<div id="header">
<p>This is the header</p>

<div id="article">
<p>This is an article</p>

<div id="footer">
<p>This is the footer.</p>

Used When Elements Overlap One Another

In the above markup, we have three <div> elements (header, article, and footer), one after another. Let’s say our page design required that the header overlapped the top portion of the article by 10 pixels, and the article element overlapped the footer element by 10 pixels.

To see what I’m talking about, here is an example page with the markup above, and a background colour and 3px coloured border applied to each of the elements, so they can be easily distinguished from one another:

3 elements displayed normally

Now, let’s look at the same page, with a negative top margin applied to all three elements:

The same 3 elements with a negative top margin

Since we’ve applied the negative margin, we can now physically see the default stacking order in action. The “article” element overlaps the “header” element for the simple reason that the “article” appears after the “header” in the markup. And the same applies for the “footer”, and why it overlaps the “article”.

Resolving a Stacking Order Problem Without Z-Index

That example shows us that z-index is not the only solution to a “stacking order” problem. Sometimes, you can resolve such an issue by simply changing the order of elements in your HTML, then positioning them accordingly.

Attempting to Implement Z-Index

But let’s say we want those 3 elements to remain exactly where they are, and, for one reason or another, could not rearrange the elements in the markup. But we needed the overlap to be reversed: we want the header to overlap the article, and the article to overlap the footer. In our CSS, let’s apply z-index values to the elements and see what happens:

The CSS now looks like this:

#header {
	background: blue;
	border: solid 3px pink;
	z-index: 3;

#article {
	background: red;
	border: solid 3px purple;
	z-index: 2;

#footer {
	background: green;
	border: solid 3px yellow;
	z-index: 1;

And here is the example page with those new styles added:

3 overlapping elements with z-index

Do you notice a difference? If you do, then you need to look again. There are no visual differences between that example and the previous one. View the source of the page, and you’ll see that, even though we’ve added a z-index value to each element, and ensured that the values represent a reverse stack order, it didn’t have any effect. Why not?

Why Doesn’t It Work?

The previously-referenced W3schools page provides the explanation. It says: “Z-index only works on elements that have been positioned (eg position:absolute;).”

In the example we’re using we can apply position: relative to our <div> selector (which will apply to all 3 elements), and the stacking order specified by our z-index values will instantly take effect. Here is the corrected demo page:

3 elements with z-index applied properly

The overlap is now reversed, because the z-index values have been used properly.

A Real-World, Practical Example

For an example of a good practical use for the z-index property, here is a site I coded that uses transparent PNGs for the tabbed navigation. First, each tab is inside of a list item with negative margins to make the tabs overlap. Next, each tab is given a specific z-index value, to reverse the natural stacking order. Then, a high z-index is applied to the “selected” tab to ensure that the stacking order is graphically visible. The CSS for those tabs would look something like this:

ul#navigation li {
	position: relative;
	margin-left: -24px;

ul#navigation li.one {
	z-index: 5;

ul#navigation li.two {
	z-index: 4;

ul#navigation li.three {
	z-index: 3;

ul#navigation li.four {
	z-index: 2;

ul#navigation li.five {
	z-index: 1;

ul#navigation li.selected {
	z-index: 100;

The server-side code dynamically adds a class of “selected” to the currently selected tab, and the z-index for that tab is given a higher value than the rest. In this example I’ve used 100 which ensures that the “selected” item will still be on top even if more tabs are added later.

Some Notes to Keep in Mind About Z-Index

The z-index property affects the position of an element on the Z-axis, which refers to how an item is stacked perpendicular to the display (instead of Y-Axis and X-Axis which refer to elements positioned parallel to the display). The higher the z-index, the closer the element will be to the user.

In IE6, select elements always appear on top of all page elements, no matter what the z-index value of any element on the page. The best way to deal with select elements appearing over top of drop down menus and other elements, is to actually make the select element invisible using display: none via JavaScript when the overlapping element appears.

The z-index property generally takes an integer as a value, but can also accept values of inherit and auto, although those values do not work properly in all browsers.

In Internet Explorer versions 6 and 7, the stacking order of z-indexed elements is essentially “reset” for any elements that are contained by a positioned element, regardless of wether or not the container (or parent) has a z-index value set. In other words, an element with a z-index value of 100 will appear underneath an element with a z-index value of 1 if the former element is contained by a positioned parent, and the latter is not. This is an incorrrect implementation of the z-index property that has evidently been corrected in IE8.

To change the z-index value of an element with JavaScript, you would use the usual “camel casing minus the hyphen”, which is generally the norm for accessing CSS properties with JavaScript (e.g. myElement.style.zIndex = "100";).


In short, the z-index property can be a powerful tool when used correctly, and can offer a very easy solution to many layout issues in graphically complex designs. As long as you remember that it only applies to elements that have a value set for the position property, you will have no trouble using this interesting CSS property.

26 Responses

  1. I’ve had a lot of headaches solved on my z-index problems by looking not only at the element I want to change the z-index on, but also on the containing parent’s siblings. This happens on absolutely positioned elements that break out of their (relatively positioned) containing parent.

    For example, if I have a drop-down navigation that I want to display over another element in the page content, I used to think I could just apply the z-index to those individual elements :

    <div id=”navigation”>
    <li>Nav Link
    Nav element with z-index of 100

    <div id=”content”>
    Element with z-index of one

    I would constantly run into problems in all browsers until I realized that the z-index’s of the parent containers, content and navigation divs in this example, must also have z-indexes set to display over one another.

    I hope this adds to the discussion. Just discovered this blog today and immediately added it to my favorite feeds. Thanks for your efforts and keep up the great work!

  2. Yeah, z-index was a bitch when I was a noob. Great breakdown of it.

  3. This is very informative. It seems I had a successful relationship with z-index on a former project, but it’s been so long. Recently I have solved layering issues by reordering them in the markup as suggested.

  4. Thanks for the great post. I had a same problem like you. But with your nicely written article I am much cleare about Z-INDEX.

  5. Andrew Durdin:

    In IE6, a Select will sit over any positioned element–except an iframe. Positioning an empty iframe beneath another positioned element is (unintuitively) sufficient to stop a select showing through.
    Firefox has a similar show-through issue with scrollbars from overflow:scroll/auto elements, which interestingly can also be worked around with an empty iframe.

  6. Great post, thanks. Z-index is finally clear in my head now! I found the colours used in the demos were a tad distracting.

  7. Nice article. Sometimes i had trouble especially with flash banner and a drop down menu. I usually go for z-index property for it.

  8. Ah, thanks for that one, z-index always gives me a headache.. I didn’d know it works on positioned elements only. :)

  9. Watch out for z-index values greater than 999999999. They will not work!

  10. Amar:

    Great breakdown of z-index property. Thanks

  11. Great post – I wish I’d learned this when I first began designing. I learned the hard way while trying to have a header element overlap a page element that z-index requires one to set the positioning – at the time, I hadn’t connected it quite yet to the x/y/z axis, and hadn’t really thought to think of design as 3D instead of 2D :)

  12. Great post. z-index can be, when fully understanding how it exactly works, very powerful. Thanks for sharing!

  13. Darrell:

    Great post! Much thanks…

    I have a question…

    How did you get the left (“My Portfolio”) tab to chop off the left on the ctconlinecme.com site?

    I looked deeply at it in Firebug, but couldn’t see how you did it.

    The “active” and “inactive” tab images are the same and I assumed that you were just covering the left edge with another image – no joy (on my part).

    You do great work! Very clean and lean…

    Thanks again for the informative post.


  14. Darrell:

    Duh! Got it! the negative left-margin gave a nice side-effect on the left.

    Thanks again…

  15. Anthony:

    Hello, first of all great article. I did learn alot however i am still having an issue with this. Here is my problem: On my website i have a header image in which i want to stay fixed at the top. Below the header i have all the content which i would like to slide up behind my header image. My markup is something like this:


    all content goes here

    When sliding the content up and down, it is on top of the header image. Any suggestions?

  16. I am currently updating my web design knowledge and this brilliant article help me get what I need in my my new design. Thank you very much :)

  17. Thanks Louis – some really helpful z-index info here.

  18. Thanks for this post! Very informative indeed, although it didn’t quite solve my z-index problem. :(
    As Slatron commented, it’s also important to keep the stack order of elements in mind. If you have 2 seperate elements both containing siblings, these siblings will always remain within the z-index level of their parent element.
    For example:

    {div id=parent1}
    {div id=child1)
    {div id=parent2}
    {div id=child2)

    parent1 has a z-index of 20
    parent2 has a z-index of 10
    In this case, child2 could never overlap parent1 or child1, because of the hierarchy of the parent-elements. However I found a way to resolve this issue:

    Don’t give parent2 any z-index !
    Give parent1 a high enough z-index to overlap with parent2. (e.g. 20 or 30)
    Give child2 a z-index high enough to overlap with parent1. (e.g. 40)

    In this way, the z-index stack-order of parent2 will start at child2, whilst parent2 itself will remain in the stack-order as it was originally. Ofcourse all the elements with a z-index should also have a position defined.
    I know it might be a little confusing, but if you don’t get it, read it a few more times..
    Here is where I found a clear explanation about z-index and stack-orders:

    • ylva:

      Thanks for your link and comment, Stefan! At last solved my problem with my z-indexes.. :)

  19. terryh:

    I am desperate to solve an issue with z-index. If you look at one of my examples:
    I am trying to make a website where I have button (menu) and when clicked they slide out a page form the right. The site never changes the whole page it just slides in new content on nav click. This page works well in some aspects. each button slides out a page like I want. One problem is that I want the content to slide out from under part of the background picture and to see all of the content I’d like to mouseover the content and it comes above the bit of picture. If you click on page (portfolio) it does this. Whats funny is this whole concept works in IE (believe it or not) but not in the other browsers. What seems to happen is the z-index’s wont let the mouseovers take affect. I’d like to change the z-index when button clicked so the active content is always on top.
    I’m newbie with jquery, sorry….
    The second issue is I’d like to close the open content when opening another content page. I have no idea how to do that in this slider case.
    I would greatly appreciate any ideas or examples.

    • When you set the z-index via jQuery, you might also need to set the “position” to “relative”, to ensure the z-index takes effect.

      In fact, you have to set the position to “relative” for all the elements that are overlaying each other. So, it’s probably best to do that in the CSS. Other than that, I’m not sure how else to help you.

      • TerryH:

        Everything is positioned. None of the jqueries I tried have done anything to affect the z-index. IE is the best example of my page working as far as being able to mouseover and see the whole content for that page. Funny because I hear everyone saying IE doesnt work. Its the only one that does. I can only assume that z-index works differently for Firefox, chrome, safari…. I find a bunch of code but no one ever show a practical example. The examples always are typically written to display something but not to adapt and use anywhere but the example. Which makes it harder to utilize.
        Thank for responding

  20. Thank you sooo much! I struggled a lot with a menu until I red the last sentence. As soon as I added a css position: relative to my menu element, it worked like a charm. Before, it slipped under the content. Thank you!

  21. Positioning saved my tookus. Thank you, kind sir.

  22. Akshay:

    Awesome tutorial this is exacting i was looking for thanks man good work keep it up .

  23. Karo:

    Thanks :*

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.