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.
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;
}
|
The challenge is as follows : try to position the red <span>
element behind the blue and green elements, without violating the following conditions:
z-index
property of elements 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.
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.
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 static
— relative
, 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.
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:
<html>
element) position
property value other than static
, and a z-index
property value other than auto
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.
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):
z-index
property (larger values “fit” above smaller values; elements with the same values are arranged in the same order as in HTML) auto
value of the z-index
property (arranged in the same order as in HTML) 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.
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.
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.
Comments
To leave a comment
Cascading CSS / CSS3 Style Sheets
Terms: Cascading CSS / CSS3 Style Sheets