Stacking Context

5 min readOct 13, 2021
Stacking Context

The stacking context is a CSS functionality that is often difficult to understand and one of the most misunderstood tool in CSS.

These terms that I’m going to explain may not be entirely clear. Things are always better understood by seeing them in action, that’s why I have created a website where you can play with the different position values and add z-index to them to see what happens.

What is stacking context?

Is a tool to control the stacking order of HTML elements. Like in image editors (like PhotoShop), you have different layers and you can put one layer after or before another. In CSS the same happens: an element can contain a set of layers.

This can be a root stacking context, as created by the html element. Or it can be a local stacking context, as created by specific properties and values.

To order the different elements we have some properties (opacity when the value is less than 1, filter when the value is not none, mix-blend-mode when the value is not normal or transform when the value is not none), but in this article I’m going to explain in more detail the best known: position and z-index.

We can create a stacking context in any part of the document and it can be created by any element. To know exactly what properties have to have the elements to create a new stacking context to see them in detail in MDN. But it’s important to pointing that:

➔ Only child elements are affected. Stacking context doesn’t affect siblings.

➔ We can have a stacking context inside another stacking context.

When you create a stacking context, the children are painted from bottom to top in this order:

  1. Children with a negative stack level (usually with `z-index: -1`)
  2. Children with position: static
  3. Children with stack level equal to 0 (usually with `z-index: auto`)
  4. Children with positive stack level (`z-index >= 1`)

Also, children with the same stack level are ordered by their origin order (the second child is painted in front of the first child).


When we positioned elements ww have 3 axes: X (width), Y (height) and Z: the third dimension. That dimension is useful to put an element in front of other elements, or behind them.

Z-index creates a layer order following the Z axis.

Z axis

The values for this property are positive or negative numbers. An element on the web page appears in front of other elements as its z-index value is higher.

To add z-index to an element, this element has to be positioned: it has to have a position value not equal to static or be in a grid or flex context.

The default value of z-index is auto, except the HTML that has z-index: 0.


The default value of position property is static. But position has other values: relative, absolute, fixed and inherit.


Is the default value. It determines that the element is not positioned, so if there’s a top/right/bottom/left/z-index property, there will be no effect on that element. We use this value, usually, to delete a real position value.


This value means the position of an element is the position of its parent. It inherits the value of the parent. If the parent is position: absolute, the child will be position:absolute;


This is the most common value (I think…) but also, a bit complicated to understand. If you add relative value without other properties like top/right/bottom/left then there will be no effect. BUT (always there’s a BUT) if the others elements are not positioned (they are static), this element will appear in front of the others, even if you don’t add z-index property. Also, you can’t put a relative element behind a static element adding z-index to the static element.

In a relative element you can add the properties top/right/bottom/left and move the element. If you add left: 20px the element will be moved 20px to the right.

An important thing it’s that children from a relative element can be positioned absolute inside that element, creating a new stacking context.


This value uses the properties top/right/bottom/left to move an element where you want. The position of this element depends on the relative parent (with position relative or absolute). And if there’s no a positioned parent, the element will depend on the whole HTML.

Also, we have to be careful because these elements are removed from the flow of elements on the page. This means that this element is not affected by other elements and it does not affect other elements. That can limit the flexibility of your site.


Elements with fixed value are positioned relative to the viewport. This means that they are going to stay in the same position even if you scroll the window. This happens because the viewport doesn’t change the position when you scroll a page.

This position type is very useful for menus for example, or cookie banners.

Also, you have to be careful because these fixed elements are always going to appear in front of other elements and sometimes they can overlap others. For example, you have a fixed menu with links to internal links. So when you click on an internal link you have to subtract the height of the menu, because if you don’t do it, the menu is going to overlap the content of your link (a way to solve this is adding scroll-margin-top: “menu height” ).


Sticky is a very powerful value. It’s a mix between relative and fixed. A sticky element depends on its positioned parent and with top/right/bottom/left you can move the element relative to its parent. The interesting part of this value is when we scroll, because the sticky element is going to become fixed and it changes its parent by the body of the HTML. Then, when you return the scroll to the original parent, it’s going to return relative.

This is very useful when you have a menu in the bottom of your principal and first element. But when you scroll down you want to have the menu on top of the page.

— — — — — —

I hope you like it!