Understanding Stacking Context and Z-index
Tags: css, html, beginners, webdev
Published: 2022-03-15 01:58:53

## What are they?
You can think of **stacking context** as a container that determines how the direct* children are ordered along the z axis(positive direction pointing towards the user). **Z-index** is used to change the default orders.

###### *Note that direct/first level children are from the point of view of stacking contexts not the DOM. So if we have the following structure `html -> div -> div -> span`, both divs and the span are siblings as long as the divs do not create additional stacking contexts.

## Why should we care?
Usually when elements are not overlapping each other it does not matter who is actually further along the z axis. But often we have elements such as header, footer or modal that will overlap other elements.

## How are stacking contexts created?
The following are the most common ways to create stacking contexts:
1. `html` element by default creates one.
2. `position:absolute;` and `position:relative;` with `z-index` set to anything other than `auto`.
3. `position:fixed;` and `position:sticky;`
4. `grid` and `flex` items with `z-index` set to anything other than `auto`.
5. Setting `isolation:isolate;`.
6. Setting `opacity` to less than 1.

For a full list check [MDN Stacking Context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context#the_stacking_context)

## How are direct children actually positioned in a stacking context?
1. The stacking context container gets placed first.
2. Elements with negative `z-index`.
3. Elements with no `z-index` or `z-index` that is invalid on that element.
4. Elements with `z-index:auto`, `z-index:0`, or positioned elements with no explicit `z-index`.
5. Elements with positive `z-index`;

###### `z-index` is only valid on positioned elements and flex/grid items.
###### Elements within the same category are ordered following the DOM order.

## Examples

Note unless otherwise specified, the elements do not create stacking contexts.

* html(default stacking context)
    * div1
        * div2
        * div3
        * div4 
            * span

In this situation, `div1, div2, div3, div4, span` are all direct children of the stacking context created by `html`. So they are all category 3 elements from above section and will be ordered following the DOM order.

* html(default stacking context)
    * div1
        * div2(position:relative; z-index:1;)
            * div3(position:absolute; z-index:9999;)
    * div4(position:relative; z-index:2;)

In this situation, we have 4 stacking contexts. Since only 2 of them, `html` and `div2` have children we don't need to worry about the other 2. 
From the pov of the `html` stacking context, it has three direct children, `div1`, `div2`, and `div4`, and their order along the z axis is the same. This means that despite `div3` having a high `z-index` it will be below `div4` since it is contained within a parent(`div2`) that is rendered below `div4`.

## Summary
Understanding how `z-index` and how it orders elements along the z axis is all about understanding what stacking context the elements are in and knowing that you can only compare direct children with each other in a stacking context.