CSS Reference Property

z-index

The z-index property is used to specify the z-order of an element when it overlaps other elements.

That is, it specifies whether the element is shown on top of other elements that it overlaps, or behind (or under) them.

The z-order is the order of the element on the z-axis. An element with a higher z-order (or z-index) will overlap other elements with lower z-orders, and will be closer to the viewer. For someone looking at the screen, an element with a higher z-order is placed in front of other elements with lower z-orders.

An element’s z-index specifies its order inside a stacking context, and can also establish a stacking context on it too.

In order to understand how z-index works, it is important to understand what stacking contexts are, how and when they are created, and how they work and interact with each other.

In short, a stacking context is a group of elements on a page, that have a common parent. The parent is the root of the stacking context, and the elements are then placed in the stacking order inside that element. The root element (html) is the “global” stacking context which contains all elements and other stacking contexts in a page.

Elements inside a stacking context are restricted to the boundaries of the context. So, an element that is contained in a stacking context can never be brought in front of an element that is contained in another stacking context with a higher z-index, even if you give your element a z-index value that is larger than the z-index of the element in the other context.

Understanding Stacking Contexts

The browser lays elements out on a page according to a natural flow. When elements overlap on the page, the browser needs to decide which element to place on top of other elements (which one is closer to the viewer)—it needs to decide which element gets a larger z-order.

A web page and every element in it has a system of coordinates. This system includes a 3-dimensional z-axis on which elements are “stacked”. The direction of the z-axis is towards the viewer. The x-axis points to the right of the screen, and the y-axis points to the bottom.

axes
The 3-dimensional coordinate system of a stacking context. The elements inside a stacking context are placed, or “stacked”, in front of each other on the z-axis. The position of an element on the z-axis, or it’s z-order, is determined by the z-index property.

Normally, the browser would lay elements out in a specific order that is specified in the CSS specification:
Elements that come first in the DOM tree are placed first, and elements that come after those are placed on top of the previous ones. But it’s not always that simple. The order mentioned works only when all the elements on the page flow naturally on the page. That is, this works when there are no elements whose position in the flow has been changed or that have been completely removed from the flow.

There are two ways in CSS that affect the flow and position of an element:

  • Positioning an element using the position property. An element with a position value other than the default static is called a positioned element.
  • Changing the flow of the element by floating it using the float property.

When the page contains floated elements, absolutely positioned elements, fixed elements, or relatively positioned elements (elements shifted from their normal position by a certain amount), along with inline elements, the browser lays them out in a different way. The elements are laid out from the closest to the viewer to furthest back as follows:

  • Positioned elements in order of appearance in the source code. Latest in the source code are closest to the viewer.
  • Inline elements—such as text and images—that are in-flow and non-positioned (their position is static).
  • Non-positioned floated elements in the order of appearance in the source code.
  • Non-positioned and non-floated block-level elements.
  • The root element—html—which is the root of the “global” stacking context which contains all elements on the page.

This is the default stacking order applied by the browser when it renders elements on the page.

default-stacking-order
3D representation of the default stacking order of the browser.

If you want to change the order in which the positioned elements, for example, are rendered on the z-axis, you can use the z-index property. For example, if you have two absolutely positioned elements that overlap at some point, and you want one of them to be shown in front of the other one even if it comes before it in the source code, you can use the z-index property to do that.

The very first important thing to note at this point is that the z-index property will only work on positioned elements. So, even if you give an element a z-index value to bring it in front of other elements, the z-index will have no effect on the element unless it is positioned; i.e. unless it has a position value other than the default static.

So, if the positioned elements have z-indexes, the elements are laid out from the closest to the viewer to furthest back as follows:

  • Positioned elements with positive z-index values. Higher values are closer to the screen. Then, in the order they appear in the source code.
  • Positioned elements with z-index: 0; or z-index: auto;.
  • Inline elements—such as text and images—that are in-flow and non-positioned (their position is static).
  • Non-positioned floated elements in the order of appearance in the source code.
  • Non-positioned and non-floated block-level elements.
  • Positioned elements with negative z-index values. Lower z-index values go further back. Then, in the order they appear in the source code.
  • The root element—html—which is the root of the “global” stacking context which contains all elements on the page.
new-stacking-order
3D representation of the new stacking order of the browser.

When we set a z-index value on a positioned element, it specifies that element’s order in the stacking context that it belongs to, and it will be rendered on the screen according to the steps mentioned above.

Another thing happens when we set an element’s z-index, though. The element that gets a z-index value other than the default value auto[1] actually creates a stacking context for all its positioned descendant elements. We mentioned earlier that every stacking context has a root element which contains all the elements inside it. When you apply the z-index property to an element, it will specify the element’s z-order in its containing context, and it will also create a new stacking context with that element as its root.

When an element becomes a new stacking context, its positioned descendants are then stacked inside it following the same rules that we mentioned earlier for the element itself. So, if we were to rewrite the rendering process above one more time, it would look like the following:

  • Stacking contexts formed by positioned elements with positive z-index values. Higher values are closer to the screen. Then, in the order they appear in the source code.
  • Positioned elements with z-index: 0; or z-index: auto;.
  • Inline elements—such as text and images—that are in-flow and non-positioned (their position is static).
  • Non-positioned floated elements in the order of appearance in the source code.
  • Non-positioned and non-floated block-level elements.
  • Stacking contexts formed by positioned elements with negative z-index values. Lower z-index values go further back. Then, in the order they appear in the source code.
  • The root element—html—which is the root of the “global” stacking context which contains all elements on the page.

[1] A positioned element with a value of z-index: auto is treated as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context should be considered part of the parent stacking context, not this new one.

So, when we use the z-index property to determine the order of positioned elements in their stack, we’re also creating “atomic” stacking contexts, where each element becomes a stacking context for all its positioned descendants.
With all this, root element becomes a stacking context for “regular” elements and for atomic stacking contexts formed by positioned elements on the page.

Image showing the global context with atomic contexts
Image showing the global context with atomic contexts

An element which becomes a new stacking context for its descendants will contain its positioned descendants inside it at all times, and, as we mentioned earlier, elements inside a stacking context are restricted to the boundaries of the context. So, any descendant of the new stacking context can never be brought in front of a descendant of another sibling stacking context with a higher z-index, even if you give that descendant a z-index value that is larger than the z-index of the element in the other context.

To better understand stacking contexts, we’re going to give some examples of objects that you can use to visualize stacking contexts on a page.

Visualizing Stacking Contexts

You can think of an element forming a stacking context as one of those stacking towers you may have played with when you were a kid. A tower is the “context” for a bunch of circular wooden pieces that you stack on top of each other.

stacking-tower
A wooden stacking tower. Circular colored pieces resemble elements inside a stacking context. The wooden tower (base) is the stacking context which contains the pieces.

Now, think of two towers next to each other, each with a stack of circles on, standing next to each other. These two towers are similar to two positioned elements on the page, each of which forms a stacking context for its descendants.

stacking-towers
Each stacking tower represents a stacking context for a bunch of wooded pieces.

It gets a little more complex (but not difficult) when two stacking contexts overlap. In order to understand what happens when stacking contexts overlap,
think of a hamburger sandwich. Yes, a hamburger sandwich.

Each hamburger contains slices of food stacked on top of each other (cheese, tomato, onions, maybe meat if you’re not a vegetarian). Each hamburger represents a stacking context for the slices of food inside it. Another hamburger next to the second one is also a stacking context for the slices inside it. Now, imagine placing two hamburgers on top of each other (are you already hungry at this point?). The two hamburgers on top of each other represent two positioned elements on a page that overlap. By stacking both hamburgers on top of each other, you’ve practically given the one on top a higher stacking order than the one in the bottom.

As you can imagine, the slices of food inside the lower hamburger cannot be positioned higher than a slice of food from the upper hamburger—they are confined inside their stacking context, and will remain within its boundaries that no matter how high a z-index one of them may get.

hamburger-stack
A wooden hamburger tower. The hamburger is the context, and the slices of food inside it are stacked on top of each other relative to their stacking context.

The following image shows an example of a real-life stacking context. This table is made up of several layers that overlap. Each layer is a context for stacking books and other stuff on it. The books on the second layer from the bottom are always below the content stacked on the upper layer. Unless the layers are changed and repositioned (given different z-orders), that will always be the case.

tables-context
A table with multiple layers each representing a stacking context

The only way the content of a stacking context A can be placed in front of the content of another stacking context B is if you give A a higher z-index than B, and if, of course, the two of them are part of the same stacking context.

The last visualizing example we’re going to talk about is probably one of the best that describe how elements are painted on a page.
The web page is practically like a painting canvas. The browser paints the elements on the canvas in a certain order just like a painter paints objects on his canvas, starting with the furthest first, and then the closest to the viewer next. The following painting analogy was explained by a “Mr. Z”:

If you think in terms of the “painters algorithm”, where objects are painted onto a scene back-to-front, then a stacking context is like a painting within a painting. You first paint everything in the stacking context back-to-front in the proper order, then slap the whole result in wherever it belongs when you come to paint its parent context.

The stacking algorithm is the same in every atomic stacking context as it is in the “global” root (html) context.

Backgrounds and borders of the element forming the stacking context always come behind (or below, depending on how you’re visualizing it) all the elements inside a context.

The main points we mentioned so far can be summarized in the following lines from the CSS Specification:

The order in which the rendering tree is painted onto the canvas is described in terms of stacking contexts. Stacking contexts can contain further stacking contexts. A stacking context is atomic from the point of view of its parent stacking context; boxes in other stacking contexts may not come between any of its boxes.

Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative to other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.

The root element forms the root stacking context. Other stacking contexts are generated by any positioned element (including relatively positioned elements) having a computed value of ‘z-index’ other than ‘auto’. Stacking contexts are not necessarily related to containing blocks.

A Simple Example

The following example shows three boxes: #first, #second, and #third. According to the normal flow of the page, if these three boxes were to be positioned absolutely and overlap, the first box will be positioned behind the other two, the third one will be positioned in front of the other two, and the second box will be positioned in between.

<div id="first">First</div>
<div id="second">Second</div>
<div id="third">Third</div>
                
#first, #second, #third {
    /* general styling here */
    /* ... */

    position: absolute;
}

#first {
    /* position offsets.. */
}

#second {
    /* position offsets... */
}

#third {
    /* position offsets... */
}
                
normal-stack
Overlapping absolutely positioned boxes are stacked by default according to their order in the source document.

Adding a positive z-index value to the first box will bring it in front of the other two boxes.

#first {
    /* ... */
    z-index: 1;
}
                
z-index-stack
The first box brought in front of the other boxes (to the top of the stack) by giving it a positive z-index value.

Giving an even higher z-index to the second box will bring it to the top of the stack.

#second {
    /* ... */
    z-index: 2;
}
                
z-index-stack-2
The second box brought in front of the other boxes (to the top of the stack) by giving it a z-index value greater than the z-index of the first box.

Last but not least, we’re going to create an atomic stacking context in the first box. We’re going to create a stacking context on the first box by using z-index: 0;. Then we’re going to try to give a descendant of the first box a very high z-index to try to bring it to the front of the second box. That, of course, is not going to work, because the descendant is confined in the stacking context of the first box, and as long as the first box is positioned behind the second box, there is no z-index value high enough that could bring the descendant in front of the second box.

z-index-stack-3
The descendant of the first box cannot be stacked in front of the second box as long as its stacking context is positioned behind the second box.

The best way to really understand stacking contexts and the z-index property is to fiddle with some code and see how that affects the layout and rendering of elements on the page. So, here is the live example for the above screenshots. Play with the values of the z-index property, change positions and stacking contexts, add and remove elements, and see how that affects the order in which the boxes are laid out on the screen.

View this demo on the Codrops Playground

Trivia & Notes

The z-index property is not the only property that creates a stacking context on an element. Other properties create stacking contexts as well, so you need to be careful when using those properties in order to avoid layout problems you may face. Many developers spend hours struggling with layout issues without realizing that a property creating a stacking context on an element is the reason why their elements aren’t being laid out the way they expect them to be.

Other properties known to create stacking contexts on elements are:

For example, if you apply an opacity to an element using opacity, any descendant of that element will be rendered below any of the element’s siblings with higher z-orders. It works the opposite way too: if an element A is stacked on top of another element B, and then its parent A’ that is behind B gets an opacity value other than 1, element A is moved back behind B because it is bound to its stacking context A’ which, in turn, is behind B. A live example of this can be seen in this excellent post by Philip Walton.

Another important note is that z-index still complies to the element’s overflow behavior. This means that if the element’s overflow is hidden using overflow: hidden; (See overflow), a positioned descendant with a z-index may be clipped off and not rendered, just like any other descendant that might overflow the element. So, if/when one of your positioned elements with a z-index isn’t being rendered, make sure its parent’s overflow is not hidden.

Official Syntax

  • Syntax:

    z-index: auto | <integer> | inherit
  • Initial: auto
  • Applies To: positioned elements
  • Animatable: yes, as an integer

Values

<integer>
This integer is the stack level (order) of the element in the current stacking context. The element also establishes a new stacking context.
auto
The stack level (order) of the element in the current stacking context is 0. The element does not establish a new stacking context unless it is the root element.
inherit
The element inherits its z-index value from its parent.

Examples

.one {
    position: relative;
    z-index: -1;
}

.two {
    position: absolute;
    z-index: 3;
}
                

Live Demo

One example where the z-index property comes in handy is fixed headers. A header usually comes first in the source document, and so, according to the normal flow, it would be rendered behind other elements on the page. By fixing the header using position: fixed;, it is moved to the top of the stack in the root element’s stacking context. Mission accomplished.

BUT, the header may be overlapped by other elements in the root context with higher z-indeces. In order to make sure the header stays on top of other elements on the page, a positive z-index value should be given to it. The actual value of the z-index depends on your knowledge of the page. If you know that there are no other positioned elements with higher stacking orders than the header, then z-index: 1 can be enough to keep the header on top. If you don’t control the content of the page and don’t know whether there are other elements with higher stacking orders, you could give it a higher value to make sure it stays on top no matter how many elements are stacked in the context; z-index: 9999; is a common value to ensure that, although it may ne unnecessary at times. As mentioned before, it depends on your page.

header {
    /* general styles can go here */
    /* ... */
    position: fixed;
    top:0;
    left: 0;
    right: 0;
    /* not needed unless you know that other elements my overlap it */
    z-index: 10;
}
                

The following is a live demo of this example. The header has been positioned and set to be fixed to the top of the page (without a z-index). Another element (blue one) on the page has also been positioned and given z-index: 1. The other element will be positioned in front of the header once they overlap. Scroll the page to see that happen. Then, add a z-index value to the header, that is greater than 1, to see how it will be positioned on top of the blue element.

View this demo on the Codrops Playground

The following shows examples of different elements with different positions and with stacking contexts. Play around with the values of the z-index and add/remove/change positions to see how that affects the stacking order.

View this demo on the Codrops Playground

Browser Support

The z-index property works in all major browsers: Chrome, Firefox, Safari, Opera, Internet Explorer, and on Android and iOS.

Written by

Last updated June 3, 2020 at 12:34 pm by Mary Lou

Do you have a suggestion, question or want to contribute? Submit an issue.