CSS Z-index and global overlay order

Lecture



The problem with z-index is that few people clearly understand how it actually works. There is nothing difficult in it, but if you have never devoted time to reading its specification, you will almost certainly not be aware of important aspects.

Do not believe me? See if you can solve the following problem.

Problem

In the HTML below, we have three <div> elements, each of which contains a <span> element. Each element, in turn, has a background color of red, green, and blue, respectively. Also, each <span> element has absolute positioning somewhere near the upper left corner of the document and slightly overlaps the other <span> elements so that it can be seen which element is on top of the other. For the first <span> element, the value of the z-index property is 1, and for the other two, this property is not set.

Here’s what the HTML and basic CSS styles look like. Below, I also added a visual demo with Codepen with full CSS.

 
1
2
3
4
5
6
7
8
9
<div>
  <span class="red">Red</span>
</div>
<div>
  <span class="green">Green</span>
</div>
<div>
  <span class="blue">Blue</span>
</div>

 
1
2
3
4
5
6
7
8
9
10
11
12
13
.red, .green, .blue {
  position: absolute;
}
.red {
  background: red;
  z-index: 1;
}
.green {
  background: green;
}
.blue {
  background: blue;
}

  CSS Z-index and global overlay order

The challenge is as follows : try to position the red <span> element behind the blue and green elements, without violating the following conditions:

  • Cannot modify and append HTML markup.
  • You cannot add / change the z-index property of elements
  • You cannot add / change the position property of elements

You should get the following picture:

Attention! Do not click on the tab with CSS, so as not to spy on the answer.

Decision

The answer is to add opacity to the first <div> element (the parent of the red <span> element) with a value slightly less than 1. Here is the CSS that was added to the example above:

 
1
2
3
div:first-child {
  opacity: .99;
}

If you are now in shock, puzzled and can not believe that transparency will affect the order of blending elements, welcome to the club. I was just as shocked when I first came across this situation.

I hope the rest of this article will clarify the situation a bit.

Overlay order

Z-index seems so simple: elements with a higher value should be above elements with a lower value, right? Not really. This is part of the problem with z-index . At first glance, it seems simple and most developers do not spend time studying the rules for its use.

Each element in an HTML document can be located either above or below other elements. This is called the overlay order. The rules of this overlay are quite clearly defined in the specification, but, as I said, most developers do not fully understand them.

When the z-index and position properties are not defined, the rules are very simple: the overlay order is exactly the same as the order of appearance in HTML, basically. (OK, in fact, everything is a bit more complicated, but as long as you do not use the negative values ​​of the margin property to overlap the line elements, you most likely will not encounter extreme cases).

If we talk about the position property, then any positioned elements (and their descendants) are displayed above any non-positioned elements. (Speaking of a “positioned” element, it means that an element has a position property other than staticrelative , absolute or fixed .)

And finally, if the z-index property is involved, then everything becomes a bit more complicated. We assume that items with a higher z-index value are above the items that have a lower z-index value, and also any items that have a z-index value set are above the items without a z-index . But everything is not so simple. First of all, z-index works only on positioned elements. If you try to set the z-index property to an element without positioning, nothing will happen. Second, the values ​​of the z-index property can create overlay contexts. Now, what seemed simple at the beginning has become more difficult.

Overlay contexts

Groups of elements with a common parent, which together move up and down in the overlay order, create what is called an overlay context. A complete understanding of the context of the overlay is the key to understanding how the z-index and the overlay order work.

As a root element, each context overlay has one HTML element. When a new overlay context is formed on an element, this overlay context encloses all its child elements in a specific place in the overlay order. This means that if an element is contained in an overlay context below an overlay order, there is no way to force it above another element with a different overlay context that is higher in the overlay order, even if you set the z-index to a billion!

New overlay contexts can be formed on an element in one of three cases:

  • When the element is the root element of the document (the <html> element)
  • When an element has a position property value other than static , and a z-index property value other than auto
  • When an element has an opacity value less than one

The first and second instances of the formation of the context overlay make sense and, as a rule, are understood by web developers (even if they do not know what they are called).

The third case (opacity) is almost never mentioned outside of the W3C specification documents.

Determining the position of an element in the overlay order

In fact, defining the global order of overlapping all elements on a page (including borders, backgrounds, text nodes, etc.) is extremely difficult and goes far beyond the scope of this article (again, I refer you to the specifications).

But for most tasks and goals, a general idea of ​​the order can go far and help keep CSS development predictable. Let's start by disrupting order in individual overlay contexts.

Overlay order within the same overlay context

Here are the basic rules to determine the order of the overlay in one overlay context (from bottom to top):

  1. The root element of the context overlay
  2. Positioned elements (and their descendants) with negative values ​​of the z-index property (larger values ​​“fit” above smaller values; elements with the same values ​​are arranged in the same order as in HTML)
  3. Non-positioned elements (arranged in the same order as in HTML)
  4. Positioned elements (and their descendants) with the auto value of the z-index property (arranged in the same order as in HTML)
  5. Positioned elements (and their descendants) with positive values ​​of the z-index property (larger values ​​“fit” above smaller values; elements with the same values ​​are arranged in the same order as in HTML)

Note: Positioned items with negative z-index values ​​will be placed first in the context of an overlay, which means that they will be displayed behind all other items. Because of this, the element has the opportunity to be behind its parent, which is usually impossible. This will only work if the parent of the element has the same context overlay and is not its root element.

Global overlay order

Having a clear understanding of how / when new overlay contexts are formed, as well as an idea of ​​the overlay order in the overlay context, finding out where a particular element will appear in the global overlay order is not so difficult.

The key to not stumble on this path is the ability to determine when new contexts overlay are formed. If you set the element to z-index at a billion and it does not move higher in the overlay order, look at its family tree to see if any of its parents form the context of the overlay. If formed, then your z-index in a billion will not give any benefit.

Conclusion

Returning to the original task, I recreated its HTML structure by adding comments inside each tag that indicate its place in the overlay order. This is the order of the original CSS rules.

 
1
2
3
4
5
6
7
8
9
<div><!-- 1 -->
  <span class="red"><!-- 6 --></span>
</div>
<div><!-- 2 -->
  <span class="green"><!-- 4 --><span>
</div>
<div><!-- 3 -->
  <span class="blue"><!-- 5 --></span>
</div>

When we add the opacity rule to the first <div> element, the blending order changes:

 
1
2
3
4
5
6
7
8
9
<div><!-- 1 -->
  <span class="red"><!-- 1.1 --></span>
</div>
<div><!-- 2 -->
  <span class="green"><!-- 4 --><span>
</div>
<div><!-- 3 -->
  <span class="blue"><!-- 5 --></span>
</div>

span.red was 6, and became 1.1. I used a dot to show that a new overlay context has formed and span.red now the first element in the new context.

I hope that you now understand why the red block was behind all the others. The original example contained only two overlay contexts, the root and another, formed by the span.red element. By adding the opacity to the parent of the span.red element, we created a third overlay context and, as a result, the z-index value of the span.red element now operates within the context of the new context. Due to the fact that the first <div> element (the one to which we applied opacity) and its related elements are not positioned and do not have the z-index property set, their order of blending is determined by the order in HTML, which means that the first element <div> and all elements in its context overlay are located behind the second and third <div> elements.

created: 2014-10-07
updated: 2021-03-13
132687



Rating 9 of 10. count vote: 2
Are you satisfied?:



Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Cascading CSS / CSS3 Style Sheets

Terms: Cascading CSS / CSS3 Style Sheets