Understanding Z-Index Stacking Order

Understanding z-index stacking order

Basics of the CSS z-index property

A Simple Concept

The z-index property is based on a simple concept: Elements with higher values will sit in front of elements with lower values along the z-axis. So if you apply z-index: 1 to div.box1, and div.box2 has a z-index: 0, then div.box1 will overlay div.box2.

In terms of the z-axis, it refers to depth on a three-dimensional plane. On your computer it can be interpreted as the plane on which objects move closer and farther from you. (Learn more about the Cartesian coordinate system.)

enter image description here
Source: Wikipedia


z-index works on positioned elements

Unless you're dealing with flex items or grid items, the z-index property works only on positioned elements. This means you can use z-index on elements with position: absolute, position: relative, position: fixed or position: sticky. If the element has position: static (the default value), or some other positioning scheme like a float, then z-index will have no effect.

As noted, although z-index, as defined in CSS 2.1, applies only to positioned elements, flex items and grid items can create a stacking context even when position is static.

4.3. Flex Item Z-Ordering

Flex items paint exactly the same as inline blocks, except that order-modified document order is used in place of raw
document order, and z-index values other than auto create a stacking context even if position is static.

5.4. Z-axis Ordering: the z-index property

The painting order of grid items is exactly the same as inline blocks, except that order-modified document order is
used in place of raw document order, and z-index values other than auto create a stacking context even if
position is static.

Here's a demonstration of z-index working on non-positioned flex items: https://jsfiddle.net/m0wddwxs/


Stacking Contexts

Once an element is positioned and a z-index is applied, a stacking context is created.

(Also see: Full list of circumstances where a stacking context is created.)

The stacking context is a set of rules for managing the positioned element with z-index, and its descendants. These rules govern the placement of child elements in the stacking order and the scope of the property's influence.

Essentially, the stacking context limits the z-index scope to the element itself, and its child elements cannot affect the stacking order of elements in another stacking context.

If you've ever tried to apply increasingly higher z-index values only to find that the element never moves out in front, you could be trying to overlay an element in a different stacking context.

Groups of elements with a common parent that move forward or backward
together in the stacking order make up what is known as a stacking
context. A full understanding of stacking contexts is key to really
grasping how z-index and the stacking order work.

Every stacking context has a single HTML element as its root element.
When a new stacking context is formed on an element, that stacking
context confines all of its child elements to a particular place in
the stacking order. That means that if an element is contained in a
stacking context at the bottom of the stacking order, there is no way
to get it to appear in front of another element in a different
stacking context that is higher in the stacking order, even with a
z-index of a billion!

~ What No One Told You About Z-Index


Stacking Order

CSS adheres to a stacking order when laying out elements on a page. These are the stacking rules when there is no z-index specified, from farthest to closest:

  1. Backgrounds and borders of the root element
  2. Non-positioned, non-floating block elements, in the order they appear in the source code
  3. Non-positioned floating elements, in the order they appear in the source code
  4. Inline elements
  5. Positioned elements, in the order they appear in the source code

If a z-index property is applied, the stacking order is modified:

  1. Backgrounds and borders of the root element
  2. Positioned elements with a z-index of less than 0
  3. Non-positioned, non-floating block elements, in the order they appear in the source code
  4. Non-positioned floating elements, in the order they appear in the source code
  5. Inline elements
  6. Positioned elements, in the order they appear in the source code
  7. Positioned elements with z-index of greater than 0

Source: W3C


Bottom line: Once you understand stacking contexts, z-index is easy.


For examples of z-index in action see: How z-index works!

For a brief but highly informative article explaining z-index (including how opacity affects the stacking order) see: What No One Told You About Z-Index

For a complete rundown on z-index, with many examples and illustrations, see: MDN Understanding CSS z-index

And for a deep dive into stacking contexts read: W3C Elaborate description of Stacking Contexts

CSS: Z-Index Stacking Context

Your element need to be at least position:relative to use z-index as this property doesn't work with static position (the default value)

as you can read here :

Note: z-index only works on positioned elements (position:absolute,
position:relative, or position:fixed).

* {  box-sizing: border-box;}
body, html, .container { height: 100%; width: 100%;}
.container { position: fixed; z-index: 300;}
#div1, #div2, #div3 { position:relative; opacity: 0.7; padding: 10px;}
#div1 { border: 1px dashed #996; background-color: #ffc; height: 33.333%; z-index: 1;}
#div2 { border: 1px dashed #900; background-color: #fdd; height: 33.333%; z-index: 2;}
#div3 { border: 1px dashed #696; background-color: #cfc; height: 33.333%; z-index: 3; transform: translateY(-40px)}
<div class='container'>  <div id="div1">DIV#1 </div>  <div id="div2">DIV#2</div>  <div id="div3">DIV#3</div></div>

Need help understanding the stacking layer order of this code that uses the z-index

For the layering order for a HTML page, it will always have the following rules.

  • An element will always be in front of it's parent. This does not say anything about other elements inside it.
  • The CSS engine will always render higher z-indexes on front of lower z-indexes. If the z-index is not defined, it will act as being 0.
  • The elements will render static elements first, then relative, then absolute, then fixed.
  • If none of these rules are different, the elements will render on the order as written (first one on background, latest one on foreground).

For layering background images, the first one will render on the foreground and the latest one on the background. The background color will always render before the background image.

CSS z-index and stacking contexts

Now, is it possible to stack the elements in the above demo in the following order (farthest to closest): #d1, #d4, #d2, #d3 ?

No, it is not possible. The farthest you can go is #d1, #d4, #d2 with the following:

#d1 { z-index: -1; position: relative; }
#d2 { }
#d3 { }
#d4 { z-index: -1; position: relative; }

... but this results in #d1 creating a stacking context for #d3, which prevents #d3 from ever being painted above #d2 or #d4 because the negative z-index of #d1 causes #d1 itself to be painted below #d4 (as two boxes with the same stack level will be painted in source order, and #d4 comes after #d1) and #d2.

Why does position:relative; appear to change the z-index?

You need to refer to the specification and more precisely the painting order to understand when each layer is painted.

Without position:relative your element is not positioned and will be painted at the step (4):


  1. For all its in-flow, non-positioned, block-level descendants in tree
    order: If the element is a block, list-item, or other block
    equivalent:

Then we paint the positioned elements (including the .mask) at the step (8)


  1. All positioned, opacity or transform descendants, in tree order that fall into the following categories

Now when you add position:relative you make the container also positioned thus it will fall in the step (8) too and as described there we consider the tree order since both don't have any z-index specified. So the .container will painted later in this case.

If you change the order of the element (you make the container before the mask) you will notice that position:relative won't have any effect because in both cases the painting order will be the same:

body {
margin: 0;
font-family: arial;
}
section {
position: relative;
background: url(https://preview.webpixels.io/boomerang-v3.6.1/assets/images/backgrounds/slider/img-41.jpg)
no-repeat left center/cover;
height: 70vh;
display: flex;
justify-content: center;
}
.container {
position: relative; /* you can remove this*/
width: 100%;
max-width: 1280px;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.mask {
position: absolute;
width: 100%;
height: 100%;
background: #3452ff;
opacity: 0.7;
}
<section>
<div class="container">
<h1>Hello World</h1>
</div>
<div class="mask"></div>
</section>

When/How does z-index break stacking context?

Every non-positioned box belongs to the same stacking context that's established by the closest ancestor that meets any of the criteria listed here, or the root element if there is no such ancestor. This means that elements don't have to be siblings of one another in order to participate in the same stacking context. They may share a distant ancestor (in HTML, every element descends from the root element), but they don't have to share a parent.

.top does not establish a new stacking context for its descendants .yes and .no as it is non-positioned and its z-index is auto. Therefore, .yes, .no and .blocker all participate in the same stacking context — the root stacking context. As a result the mere fact that .yes has a higher z-index than .blocker causes it to be painted in front.

Note that while each of .yes, .no and .blocker does establish its own stacking context, the stacking contexts they establish are not pertinent here; it's the stacking context that they participate in, and they all participate in the same root stacking context.

Why does clip-path (and other properties) affect the stacking order (z-index) of elements later in DOM?

From the specifcation:

A computed value of other than none results in the creation of a stacking context the same way that CSS opacity does for values other than 1.

Then considering the painting order:


  1. All positioned, opacity or transform descendants, in tree order that fall into the following categories:
    1. All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order.
      For those with 'z-index: auto', treat the element 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.
      For those with 'z-index: 0' treat the stacking context generated atomically.
    2. All opacity descendants with opacity less than 1, in tree order, create a stacking context generated atomically.
    3. All transform descendants with transform other than none, in tree order, create a stacking context generated atomically.

The element with clip-path is painted at the step (8) and the image will be painted before if has no position set


  1. For all its in-flow, non-positioned, block-level descendants in tree order: If the element is a block, list-item, or other block equivalent ...

If you add position:relative to image it will be postioned and will fall under the step (8) and the tree order will decide making it above the clip-path element

Here is the same code with opacity where you will have the same painting order: