Aman Explains

Settings

Understanding stacking rules for the HTML elements

March 21, 2022• ☕️ 4 min read

I thought I knew enough about how positioning and z-index works in HTML and CSS. But recently, I learned a new concept that completely took me by surprise. This article aims to share that knowledge with you and help you better understand how the z-index works in HTML. Let’s get started.

Imagine you have two HTML div elements with exactly the same dimensions. The first element has position absolute and a blue background. The second one has a position relative and a red background as shown below.

<style>
  div {
    height: 200px;
    width: 200px;
  }

  .first {
    position: absolute;
    background: blue;
  }

  .second {
    position: relative;
    background: red;
  }
</style>

<div class="first">First element</div>
<div class="second">Second element</div>

What colour would you see on the page: blue or red?

If you think the answer is blue because the absolute positioned element will be taken out of the [normal page flow], and then the relative positioned element should occupy that space underneath (as if the first element never existed), I am afraid you are wrong, and I was too 😛.

The correct answer is red 🤯.

Here’s the codepen example to demonstrate that:

Stacking without the z-index property

To understand this, we need to look at how elements are stacked in HTML when they don’t have any z-index property assigned.

As per Mozilla documentation, when z-index property is not specified on the elements, they are stacked in the following order (from bottom to top)

  1. The background and borders of the root element
  2. Descendant non-positioned blocks, in order of appearance in the HTML
  3. Descendant positioned elements, in order of appearance in the HTML

Focusing on the third point above, we can conclude that the stack level of the positioned element will be exactly how their order of appearance is in the HTML. This is irrespective of their positioning (absolute, relative, sticky, or fixed) type.

In our example code above, even though the first div has been taken out of the normal page flow, the relative element will be stacked above the first element as it appears second in the HTML order. And thus, you will see the red colour instead of the blue 😍.

Changing the stack level with z-index

What we just learned is the default stacking behaviour of the elements without the z-index property. If you want to rearrange the stack order, you can do so by specifying z-index property on a positioned element.

The z-index can have any integer value that represents the position of an element along the z-axis. By default, the initial value of the z-index is auto. It means that when no z-index property is specified, elements are placed on layer 0—the default rendering layer.

You can think of the z-index as a numerical value of the rendering layer.

Layers on the page have a numerical value equal to their z-index

Looking at our previous example above, if we specify z-index: 1 to the first div element, it will position the element on layer 1. The second element will be on layer 0. As a result you would see the blue colour.

<style>
  div {
    height: 200px;
    width: 200px;
  }

  .first {
    position: absolute;
    background: blue;
    z-index: 1;
  }

  .second {
    position: relative;
    background: red;
  }
</style>

<div class="first">First element</div>
<div class="second">Second element</div>

The stack order of the layers for the previous example would be like this:

higher z-index value element will stack on top of smaller value

Now, if we had the third non-positioned element (position: static) in the HTML example (appearing last in the HTML order), applying z-index value wouldn’t have affected it’s stack level. It will always be at the default rendering layer (layer 0).

The z-index only affects elements that have a position value other than static (the default)

But, if we had specified a negative z-index value for the second positioned element, it would have stacked underneath the third element. Let’s look at another example to clarify that.

<style>
  body {
    margin-top: 100px;
  }
  div {
    opacity: 0.7;
    border: 4px dotted;
    margin-top: -40px;
    text-align: center;
  }

  .first {
    width: 200px;
    height: 400px;
    position: absolute;
    background: blue;
    z-index: 1;
  }

  .second {
    width: 300px;
    height: 300px;
    position: relative;
    background: red;
    z-index: -1;
  }
 
 .third {
    width: 400px;
    height: 150px;
    background: green;
    z-index: 2;
 }
...
</style>

<div class="first">First element</div>
<div class="second">Second element</div>
<div class="third">Third element</div>

The following picture should make it clear:

negative z-index element will be stacked below a non-positioned element

And here’s the Codepen demo to play with:


Final words

There’s one more important concept called stacking context which requires a separate article all together. The short explanation is that when a stacking context is formed, it creates a boundary around the descendant elements, and their z-index values can only influence their stacking order within the same context. The z-index value of elements inside one stacking context can’t influence the stacking order of other elements residing in a different stacking context.

The scope of the z-index is not global

Nonetheless, the stacking rules we just learned still applies as they are to the elements within the same stacking context. I highly recommend reading the following in-depth articles to understand how stacking context works.


Amandeep Singh

Written by Amandeep Singh. Developer @  Avarni  Sydney. Tech enthusiast and a pragmatic programmer.