CSS - How to use z-index property 🚀

January 11, 2021

The hassle around the Z-index

Z-Index is one of the most confusing and unintuitive properties in CSS, but it’s actually pretty simple once you understand it. Your first instinct is probably to think that you can just set z-index on any element and that that alone is going to determine its stacking order. This is WRONG. 👉 The z-index property is used to control the Z axis positioning of elements.

It’s very useful when you have multiple elements that overlap each other, and you need to decide which one is visible, as nearer to the user, and which one(s) should be hidden behind it.

👉 This property takes a number (without decimals) and uses that number to calculate which elements appear nearer to the user, in the Z axis.

The higher the z-index value, the more an element is positioned nearer to the user.

🛑 Z-index only applies to positioned elements.

A positioned element is an element who’s position property is NOT static (eg. relative, absolute, fixed). Setting a z-index on an unpositioned element does nothing. If a positioned element has a z-index of X, then all of its children will also be stuck with a z-value of X

You can change the z-index of any child elements all you want, but that won’t do anything! (Note: z-value is not an actual CSS term. I only use it because z-index technically defaults to “auto” and can be set to whatever you want, even if it does nothing)

<div id="parent" style="position: relative; z-index: 6;">
  <div id="child" style="position: relative: z-index: 7;">
    <div id="grandchild" style="position: relative; z-index: 9;" >
    </div>
  </div>
</div>

The z-value of each of these elements is 6, and there’s no way to change that without modifying the z-index of #parent. In technical terms, a stacking context is formed when a positioned element has a z-index.

👉 A stacking context is a single atomic unit composed of a parent along with its children. All elements within a stacking context are bound to the z-value set by the non-root parent (in the code box above #parent).

(Non-root just means that it’s not the <html> tag. The root <html> tag technically forms a stacking context, but any z-index on it is meaningless.)`

you can create stacking contexts within stacking contexts, but all child stacking contexts will be bound to the z-value of the outermost (non-root) stacking context.

In the example above, three stacking contexts are formed, and they’re nested. The z-value of all three contexts is bound to the z-index of #parent, which is 6.

Stacking Contexts:

#parent (z-value: 6)
  #child
    #grandchild

👉 Setting the z-index on a positioned element is only one of many ways to create a stacking context. There are various CSS properties that automatically create a stacking context on an element, regardless of whether or not a z-index is set.`

The full list is here, but here are some common properties that automatically create new stacking contexts:

👉 position: fixed

👉 elements with a transform value other than "none"

👉 elements with an opacity value less than 1.

So any element with position: fixed or transform: translateY(50%) is going to form a new stacking context regardless of whether a z-index has been set on that element.

When deciding which element should be visible and which one should be positioned behind it, the browser does a calculation on the z-index value.

The default value is auto, a special keyword. Using auto, the Z axis order is determined by the position of the HTML element in the page - the last sibling appears first, as it’s defined last.

By default elements have the static value for the position property. In this case, the z-index property does not make any difference - it must be set to absolute, relative or fixed to work.

.my-first-div {
	position: absolute;
	top: 0;
	left: 0;
	width: 600px;
	height: 600px;
	z-index: 10;
}

.my-second-div {
	position: absolute;
	top: 0;
	left: 0;
	width: 500px;
	height: 500px;
	z-index: 20;
}

The element with class .my-second-div will be displayed, and behind it .my-first-div.

👉 Actually any number can be used. Negative numbers too. It’s common to pick non-consecutive numbers, so you can position elements in the middle. If you use consecutive numbers instead, you would need to re-calculate the z-index of each element involved in the positioning.

Up next