How can you figure out the highest z-index in your document?
JavascriptHtmlCssZ IndexJavascript Problem Overview
In order to set a div containing a transparent text image as the highest z-index in my document, I picked the number 10,000 and it solved my problem.
Previously I had guessed with the number 3 but it had no effect.
So, is there a more scientific way of figuring out what z-index is higher than that of all of your other elements?
I tried looking for this metric in Firebug but couldn't find it.
Javascript Solutions
Solution 1 - Javascript
Stealing some code from abcoder site for the sake of clarity:
var maxZ = Math.max.apply(null,
$.map($('body *'), function(e,n) {
if ($(e).css('position') != 'static')
return parseInt($(e).css('z-index')) || 1;
}));
Solution 2 - Javascript
You could call findHighestZIndex
for a particular element type such as <div>
like this:
findHighestZIndex('div');
assuming a findHighestZindex
function that is defined like this:
function findHighestZIndex(elem)
{
var elems = document.getElementsByTagName(elem);
var highest = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1);
for (var i = 0; i < elems.length; i++)
{
var zindex = Number.parseInt(
document.defaultView.getComputedStyle(elems[i], null).getPropertyValue("z-index"),
10
);
if (zindex > highest)
{
highest = zindex;
}
}
return highest;
}
Solution 3 - Javascript
Using ES6 a cleaner approach
function maxZIndex() {
return Array.from(document.querySelectorAll('body *'))
.map(a => parseFloat(window.getComputedStyle(a).zIndex))
.filter(a => !isNaN(a))
.sort()
.pop();
}
Solution 4 - Javascript
I’d like to add my ECMAScript 6 implementation that I use in one of my UserScripts. I’m using this one to define the z-index
of specific elements so that they always appear the highest.
In JS, you can additionally set certain attributes or class names to elements that you may want to exclude. For instance, consider your script setting a data-highest
attribute on an element that you want to appear as the highest element (e.g. a popup); and consider an element with class name yetHigher
that you don’t control, which should be even higher (e.g. a custom context menu). I can exclude these elements with a chained :not
selector. Note that :not([data-highest], .yetHigher)
is possible, but experimental, and only has limited browser support as of January 2021.
let highestZIndex = 0;
// Then later, potentially repeatedly
highestZIndex = Math.max(
highestZIndex,
...Array.from(document.querySelectorAll("body *:not([data-highest]):not(.yetHigher)"), (elem) => parseFloat(getComputedStyle(elem).zIndex))
.filter((zIndex) => !isNaN(zIndex))
);
The lower five lines can run multiple times and update the variable highestZIndex
repeatedly by finding out the maximum between the current highestZIndex
value and all the other computed z-indexes of all elements. The filter
excludes all the "auto"
values.
Solution 5 - Javascript
There isn't a default property or anything, but you could write some javascript to loop through all elements and figure it out. Or if you use a DOM management library like jQuery, you could extend its methods (or find out if it supports it already) so that it starts tracking element z-indices from page load, and then it becomes trivial to retrieve the highest z-index.
Solution 6 - Javascript
I believe what you are observing is Voodoo. Without access to your complete style sheet I can of course not tell reliably; but it strikes me as likely that what really has happened here is that you have forgotten that only positioned elements are affected by z-index
.
Additionally, z-index
es aren't assigned automatically, only in style sheets, which means that with no other z-index
ed elements, z-index:1;
will be on top of everything else.
Solution 7 - Javascript
I guess you have to do this yourself ...
function findHighestZIndex()
{
var divs = document.getElementsByTagName('div');
var highest = 0;
for (var i = 0; i < divs .length; i++)
{
var zindex = divs[i].style.zIndex;
if (zindex > highest) {
highest = zindex;
}
}
return highest;
}
Solution 8 - Javascript
The best way to solve this problem is, in my opinion, just to set yourself conventions for what kinds of z-index
es are used for different kinds of elements. Then, you'll find the correct z-index
to use by looking back at your documentation.
Solution 9 - Javascript
The "ES6" version above is less efficient than the first solution because it does multiple redundant passes across the full array. Instead try:
findHighestZ = () =>
[...document.querySelectorAll('body *')]
.map(elt => parseFloat(getComputedStyle(elt).zIndex))
.reduce((highest, z) => z > highest ? z : highest, 1)
In theory it would be even quicker to do it in one reduce step, but some quick benchmarking showed no significant difference, and the code is gnarlier
Solution 10 - Javascript
Using jQuery:
if no elements supplied, it checks all elements.
function maxZIndex(elems)
{
var maxIndex = 0;
elems = typeof elems !== 'undefined' ? elems : $("*");
$(elems).each(function(){
maxIndex = (parseInt(maxIndex) < parseInt($(this).css('z-index'))) ? parseInt($(this).css('z-index')) : maxIndex;
});
return maxIndex;
}
Solution 11 - Javascript
I had to do this for a project recently, and I found that I benefitted a lot from @Philippe Gerber's great answer here, and @flo's great answer (the accepted answer).
The key differences to the answers referenced above are:
- Both the CSS
z-index
, and any inlinez-index
style are calculated, and use the larger of the two for comparison and calculation. - Values are coerced into integers, and any string values (
auto
,static
, etc) are ignored.
Here is a CodePen for the code example, but it's included here as well.
(() => {
/**
* Determines is the value is numeric or not.
* See: https://stackoverflow.com/a/9716488/1058612.
* @param {*} val The value to test for numeric type.
* @return {boolean} Whether the value is numeric or not.
*/
function isNumeric(val) {
return !isNaN(parseFloat(val)) && isFinite(val);
}
/**
* Finds the highest index in the current document.
* Derived from the following great examples:
* [1] https://stackoverflow.com/a/1118216/1058612
* [2] https://stackoverflow.com/a/1118217/1058612
* @return {number} An integer representing the value of the highest z-index.
*/
function findHighestZIndex() {
let queryObject = document.querySelectorAll('*');
let childNodes = Object.keys(queryObject).map(key => queryObject[key]);
let highest = 0;
childNodes.forEach((node) => {
// Get the calculated CSS z-index value.
let cssStyles = document.defaultView.getComputedStyle(node);
let cssZIndex = cssStyles.getPropertyValue('z-index');
// Get any inline z-index value.
let inlineZIndex = node.style.zIndex;
// Coerce the values as integers for comparison.
cssZIndex = isNumeric(cssZIndex) ? parseInt(cssZIndex, 10) : 0;
inlineZIndex = isNumeric(inlineZIndex) ? parseInt(inlineZIndex, 10) : 0;
// Take the highest z-index for this element, whether inline or from CSS.
let currentZIndex = cssZIndex > inlineZIndex ? cssZIndex : inlineZIndex;
if ((currentZIndex > highest)) {
highest = currentZIndex;
}
});
return highest;
}
console.log('Highest Z', findHighestZIndex());
})();
#root {
background-color: #333;
}
.first-child {
background-color: #fff;
display: inline-block;
height: 100px;
width: 100px;
}
.second-child {
background-color: #00ff00;
display: block;
height: 90%;
width: 90%;
padding: 0;
margin: 5%;
}
.third-child {
background-color: #0000ff;
display: block;
height: 90%;
width: 90%;
padding: 0;
margin: 5%;
}
.nested-high-z-index {
position: absolute;
z-index: 9999;
}
<div id="root" style="z-index: 10">
<div class="first-child" style="z-index: 11">
<div class="second-child" style="z-index: 12"></div>
</div>
<div class="first-child" style="z-index: 13">
<div class="second-child" style="z-index: 14"></div>
</div>
<div class="first-child" style="z-index: 15">
<div class="second-child" style="z-index: 16"></div>
</div>
<div class="first-child" style="z-index: 17">
<div class="second-child" style="z-index: 18">
<div class="third-child" style="z-index: 19">
<div class="nested-high-z-index">Hello!!! </div>
</div>
</div>
</div>
<div class="first-child">
<div class="second-child"></div>
</div>
<div class="first-child">
<div class="second-child"></div>
</div>
<div class="first-child">
<div class="second-child"></div>
</div>
</div>
Solution 12 - Javascript
Array.reduce()
Here's another solution to determine the topmost z-index
that uses Array.reduce()
:
const max_zindex = [...document.querySelectorAll('body *')].reduce((accumulator, current_value) => {
current_value = +getComputedStyle(current_value).zIndex;
if (current_value === current_value) { // Not NaN
return Math.max(accumulator, current_value)
}
return accumulator;
}, 0); // Default Z-Index Rendering Layer 0 (Zero)
Solution 13 - Javascript
ShadowRoot solutions
We must not forget about custom-elements and shadow-root content.
function computeMaxZIndex() {
function getMaxZIndex(parent, current_z = 0) {
const z = parent.style.zIndex != "" ? parseInt(parent.style.zIndex, 10) : 0;
if (z > current_z)
current_z = z;
const children = parent.shadowRoot ? parent.shadowRoot.children : parent.children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
current_z = getMaxZIndex(child, current_z);
}
return current_z;
}
return getMaxZIndex(document.body) + 1;
}
Solution 14 - Javascript
A solution highly inspired from the excellent idea of @Rajkeshwar Prasad .
/**
returns highest z-index
@param {HTMLElement} [target] highest z-index applyed to target if it is an HTMLElement.
@return {number} the highest z-index.
*/
var maxZIndex=function(target) {
if(target instanceof HTMLElement){
return (target.style.zIndex=maxZIndex()+1);
}else{
var zi,tmp=Array.from(document.querySelectorAll('body *'))
.map(a => parseFloat(window.getComputedStyle(a).zIndex));
zi=tmp.length;
tmp=tmp.filter(a => !isNaN(a));
return tmp.length?Math.max(tmp.sort((a,b) => a-b).pop(),zi):zi;
}
};
#layer_1,#layer_2,#layer_3{
position:absolute;
border:solid 1px #000;
width:100px;
height:100px;
}
#layer_1{
left:10px;
top:10px;
background-color:#f00;
}
#layer_2{
left:60px;
top:20px;
background-color:#0f0;
z-index:150;
}
#layer_3{
left:20px;
top:60px;
background-color:#00f;
}
<div id="layer_1" onclick="maxZIndex(this)">layer_1</div>
<div id="layer_2" onclick="maxZIndex(this)">layer_2</div>
<div id="layer_3" onclick="maxZIndex(this)">layer_3</div>
Solution 15 - Javascript
If you're looking to show the IDs of all elements with the highest z indices:
function show_highest_z() {
z_inds = []
ids = []
res = []
$.map($('body *'), function(e, n) {
if ($(e).css('position') != 'static') {
z_inds.push(parseFloat($(e).css('z-index')) || 1)
ids.push($(e).attr('id'))
}
})
max_z = Math.max.apply(null, z_inds)
for (i = 0; i < z_inds.length; i++) {
if (z_inds[i] == max_z) {
inner = {}
inner.id = ids[i]
inner.z_index = z_inds[i]
res.push(inner)
}
}
return (res)
}
Usage:
show_highest_z()
Result:
[{ "id": "overlay_LlI4wrVtcuBcSof", "z_index": 999999}, { "id": "overlay_IZ2l6piwCNpKxAH", "z_index": 999999}]
Solution 16 - Javascript
Robust solution to find maximum zIndex in NodeList
- You should check both
getComputedStyle
andstyle
object provided by node itself - Use Number.isNaN instead of isNaN because of
isNaN("") === false
function convertToNumber(value) {
const asNumber = parseFloat(value);
return Number.isNaN(asNumber) ? 0 : asNumber;
}
function getNodeZIndex(node) {
const computedIndex = convertToNumber(window.getComputedStyle(node).zIndex);
const styleIndex = convertToNumber(node.style.zIndex);
if (computedIndex > styleIndex) {
return computedIndex;
}
return styleIndex;
}
function getMaxZIndex(nodeList) {
const zIndexes = Array.from(nodeList).map(getNodeZIndex);
return Math.max(...zIndexes);
}
const maxZIndex = getMaxZIndex(document.querySelectorAll("body *"));
Solution 17 - Javascript
Very simple code using map
and filter
function calMaxZIndex() {
return Array.from(document.querySelectorAll('body *'))
.map(a => parseFloat(window.getComputedStyle(a).zIndex || a.style.zIndex))
.filter(a => !isNaN(a))
.sort()
.pop()
}
function getMax() {
const max = calMaxZIndex() ?? 0
console.log({
max
})
}
getMax()
#ticket-box {
text-align: center;
position: fixed;
top: 0;
right: 0;
width: 100%;
background-color: #e9d295;
padding: 5px;
z-index: 6;
}
<div id="menu">
<a href="javascript:void(0);" onclick="closeMenu();" style="color: #ffffff; position: absolute; top: 15px; right: 15px;text-decoration: none;">CLOSE</a>
<ul style="text-align:center;list-style-type:none;">
<li><a href="#">FILM</a></li>
<li><a href="#">MUSIC</a></li>
<li><a href="#">SPORTS</a></li>
<li><a href="#">FINANCE</a></li>
</ul>
</div>
<div id="ticket-box">Have you bought your tickets for friday's event? No?! <a href="#">Grab yours now!</a></div>
<center><a href="javascript:void(0);" onclick="revealMenu();" style="display: inline-block; color: #333333; margin-top: 90px;">MENU</a></center>
Solution 18 - Javascript
Based on previous answers:
function with some modifications
let zIndexMax = () =>
[...document.querySelectorAll('body > *')]
.map(elem => parseInt(getComputedStyle(elem).zIndex, 10) || 0)
.reduce((prev, curr) => curr > prev ? curr : prev, 1);
Prototype
HTMLElement.prototype.zIndexMax = function () {
return [...this.children]
.map(elem => parseInt(getComputedStyle(elem).zIndex, 10) || 0)
.reduce((prev, curr) => curr > prev ? curr : prev, 1);
}
usage
document.querySelector('body').zIndexMax();
Solution 19 - Javascript
After looking through a lot of solutions here on StackOverflow - I've seen that none of them actually works correctly and considers how is zIndex actually working. I have written a solution that also takes into consideration the stacking context. You can refer to this article to understand how stacking context works in CSS.
const getZIndex = el => {
const computedStyle = getComputedStyle(el, null)
const zIndex = computedStyle.getPropertyValue('z-index')
return zIndex !== 'auto' ? parseInt(zIndex) : null
}
const getZIndexWithinStackingContext = (el, context) => {
let zIndex = getZIndex(el)
if (!zIndex) return null
let result = zIndex
while (el.parentElement !== context) {
el = el.parentElement
zIndex = getZIndex(el)
if (zIndex) {
result = zIndex
}
}
return result
}
const createZIndex = (overVisibleOnly = false, context = document.body) => {
const elements = [...document.querySelectorAll('body *')]
let highestZIndex = 0
elements.forEach(el => {
if (overVisibleOnly) {
const isVisible = !!el.offsetParent
if (!isVisible) return
}
const zIndex = getZIndexWithinStackingContext(el, context)
if (zIndex && zIndex > highestZIndex) {
highestZIndex = zIndex
}
})
return highestZIndex + 1
}
Note that this solution considers all elements, and not only positioned ones because they can become positioned after some class is added. But you can fix this easily by just adding a check for the position computed style property.