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.
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 aposition
value other than the defaultstatic
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
isstatic
). - 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.
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;
orz-index: auto;
. - Inline elements—such as text and images—that are in-flow and non-positioned (their
position
isstatic
). - 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. Lowerz-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.
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;
orz-index: auto;
. - Inline elements—such as text and images—that are in-flow and non-positioned (their
position
isstatic
). - 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. Lowerz-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.
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.
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.
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.
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.
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... */ }
Adding a positive z-index
value to the first box will bring it in front of the other two boxes.
#first { /* ... */ z-index: 1; }
Giving an even higher z-index
to the second box will bring it to the top of the stack.
#second { /* ... */ z-index: 2; }
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.
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.
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:
-
opacity
-
filter
-
clip-path
-
transform
- CSS Regions
- Paged Media
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.
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.
Browser Support
The z-index
property works in all major browsers: Chrome, Firefox, Safari, Opera, Internet Explorer, and on Android and iOS.
Further Reading
- CSS Visual Formatting Model
- Elaborate Description of Stacking Contexts – W3C
- Detailed Look at Stacking in CSS by Tim Kadlec
- What You May Not Know About The z-index Property on Web Design Tutsplus
- A Detailed Look At The z-index CSS Property by Louis Lazaris
- The z-index Property – A Comprehensive Look on Smashing Magazine
- What No One Told You About The z-index Property by Philip Walton
- Z-Index And The CSS Stack: Which Element Displays First? by Steven Bradley