
Elements on web pages are generally located side by side or under each other. But sometimes the design requires overlapping elements. For example, a drop-down menu navigation, preview panels when you hover the cursor, useless banners about cookies and, of course, countless pop-up windows that require your immediate attention.
In these situations, the browser must somehow decide which elements to show “from above” and which elements to keep in the background, completely or partially closed. The relatively complex set of rules in the CSS standard determines the default
overlay order for each page element (perhaps everything in the world can be called “relatively complex”, but it is immediately alarming that the standard comes with a special application entitled
“Detailed description of overlay contexts” ).
If the default order does not suit, then developers resort to the
z-index
property: it gives control over the virtual z axis (depth), which conceptually passes “through” the page. Thus, an element with a higher
z-index
displayed “closer” to the user, that is, it is drawn over elements with lower indices.
An interesting property of the
z
axis is that it has no natural boundaries. Horizontal and vertical axes are usually limited by the expected size of the display. We do not expect any elements to be located at “1000000px on the left” or “-3000em above”: they will either become invisible or cause unpleasant scrolling. (Unless you are reading this article at a time when there are millions of pixels wide displays everywhere. If so, I urge you to stop reading and launch a web page project for a trillion dollars).
')
But the
z-index
values are dimensionless and have meaning only in relative terms: a page with two elements will look the same if the indices
z
are
1
and
2
or
−10
and
999
. Combined with the fact that pages are often assembled from components developed in isolation, this leads to the curious art of choosing appropriate z-indices.
How to ensure that your annoying pop-up window is accurately displayed on top of all the elements on the page, if you do not know how many of them, who wrote them, and how much
they wanted to be at the top? That's when you put your z-index on 100, or maybe 999, or maybe purely just in case, on 99999, to ensure that your win is certain.
At least that's how I write my CSS. In the rest of this post, we will look at millions of z-indices and see what other web developers are doing.
Data retrieval
The first step was to collect a large set of z-index values from existing web pages. To do this, I turned to
Common Crawl , an accessible, very large and wonderful repository of pages from the Internet. The data is hosted on S3, so you can efficiently query it from the AWS cluster. Fortunately, there are several tutorials on the Internet showing how to do this.
My complex z-index extractor includes searching every page for all matches of the following regular expression:
re.compile(b'z-index *: *(-?[0-9]+|auto|inherit|initial|unset)')
Once the values are defined, the standard map-reduce task for the number of entries remains. Fortunately, I am not the first who wanted to count the occurrences of all sorts of things in the sample, and that was enough to adapt
one of many examples . (Almost all of my personal code is the regular expression above.)
Thanks to a
very detailed blog article, I was able to deploy the code on the
Elastic Map Reduce cluster, and I started scanning the
archive of pages for March 2019 . This particular archive is divided into 56,000 parts, of which I randomly chose 2500, or about 4.4%. This number is nothing special, except that it translates roughly into the price I was willing to invest in this experiment. After a terrible night in the hope that I had made wrong predictions, I got the results, extracted from 112.7 million pages. (I have to note that all these are HTML pages. I didn’t go too far into this question, but it seems that Common Crawl does not index external style sheets, and as a result I only extract values from embedded CSS. I’ll leave it as an exercise for the reader to determine whether the distribution obtained corresponds to what you get from external style sheets).
Most common values
My scan yielded a total of about 176.5 million z-index values, of which 36.2 thousand were unique.
So what are the most common?
The picture shows the top 50. Note that the
y axis is logarithmic and shows relative frequencies. For example, the most common value of 1 is 14.6% of all entries found in the sample. In general, the top 50 is about all 80% of the collected values.

The first observation is that positive values dominate. The only negative element in the top 50 is
−1
(the second most prevalent
−2
is in 70th place). Perhaps this tells us that people are usually more interested in bringing things up than to hide them in the background.
As a rule, most top values have one of the following properties:
- They are small: for example, all numbers from 0 to 12 are in the top 50.
- These are powers of ten or multiples: 10, 100, 1000, 2000, ...
- They are "close" to the degree of ten: 1001, 999, 10001, ...
These patterns are consistent with the fact that people choose large “familiar” values (degrees of ten), and then, perhaps, to adjust the relative depth inside the component — the values are slightly higher or lower.
It is also interesting to look at the most common values that do not fit into any of these patterns:
At 36th place, we see 2147483647. Many programmers immediately recognize this number as
INT_MAX
, that is, 2
31 −1. Probably, people reason like this: since this is the largest value for a (signed) integer, no z-index will be higher, so my element with an INT_MAX index will always be at the top. However, MDN says the
following about integers in CSS:
There is no official value range of type <integer>
. Opera 12.1 supports values up to 2 15 -1, IE - up to 2 20 -1, and other browsers even higher. Throughout the existence of CSS3 values, several discussions were held on establishing the minimum supported range: the last decision was made in April 2012 during the LC phase, then the range [-2 27 -1; 2 27 -1], but other values have been proposed, such as 2 24 -1 and 2 30 -1. However, the most recent specification at the moment no longer indicates the domain of definition of this data type.
Thus, not only is there no agreed maximum value, but in each documented specification or standard clause
INT_MAX
actually out of range.
On the 39th place we have 8675309, in which I personally did not see anything remarkable. But for more than half a million developers, obviously, it makes sense. I suspect that you will either instantly recognize this number, or you will not understand its meaning at all, depending on where and when you grew up. I will not give out spoilers, the answer is hidden in just
one search .
The last two numbers, which seemed a bit out of place, are 1030 and 1050, in 42nd and 45th places, respectively. Another quick search revealed that these
are the default z-index values for the classes
navbar-fixed
and
modal
in Bootstrap.
Distribution of values
Although the vast majority of all
z-index
values fall into a small number of options, it may be interesting to look at the wider distribution of the assembled set. For example, Figure 2 shows the frequency of all values between -120 and 260.

In addition to the dominance of round numbers, we see an almost fractal quality of patterns on several levels. For example, the midpoint between two local maxima is often itself a (smaller) local maximum: it is 5 between 1 and 10, 15 between 10 and 20, 50 between 1 and 100, and so on.
We can confirm this effect on a wider range: the following figure shows the frequencies of all values from -1200 to 2600, rounded off to a lower absolute value to ten, that is, numbers like 356 and 359 counted as 350. The graph is very similar to the previous one. As you can see, the structure is basically preserved when considering values an order of magnitude more.

Finally, in the last illustration, all the positive
z-index
values from 1 to 9999999999 are grouped by the first digit (horizontal axis) and the number of digits (vertical axis).
Positive z-index
values, grouped by first digit and number of digits. The dimensions are proportional to the total frequency of the band. Click on the group for more information.We can intuitively represent each group as a pattern of values, for example,
3xxx
for all four-digit values starting with 3. Each group is displayed as a rectangle whose size is proportional to the frequency of the pattern. The figure shows, for example, that for each order of magnitude, i.e. a number of groups, the frequencies follow a similar trend, with values starting from 1 being the most common, then 9, then 5.
The hue of each group is set based on its entropy. The yellow groups have the highest entropy, while the blue ones have the lowest. This helps to identify patterns where developers usually choose the same values, or those where the values are distributed more evenly (note that the entropy of our entire data set is 6.51 bits).
Conclusion
Although it was definitely interesting to collect and research this data set, I’m sure there are better statistics, visualizations and explanations awaiting production and presentation. If you want to try it, feel free to download and distribute the
z-index-data.csv file .
Perhaps you will succeed where I failed, and find a way to include in the graph the largest
z-index
value I found, namely 10
1242 -1.
Yes, that number 9 is repeated 1242 times. I really hope that they were finally able to show their <div> above.