Rudie
Rudie

Reputation: 53881

How do I get the (element with the) highest CSS z-index in a document?

The question couldn't be easier. The z-index values are assigned by style=... or className, with Javascript or not. I don't think it matters. How do I find (with Javascript) the highest z-index? (The element it's used in would be nice, but not necessary.)

You can't use the (new) querySelector, because it doesn't query CSS values. Is there someway to query CSS? (Not the stylesheets, but the actual used values.)

Grazi


Get top 5 elements + z-indexes:

Array.from(document.querySelectorAll('*')).map(el => [el, getComputedStyle(el).zIndex]).filter(v => !isNaN(parseInt(v[1]))).sort((a, b) => b[1] - a[1]).slice(0, 5)

Upvotes: 6

Views: 8437

Answers (5)

Praveen
Praveen

Reputation: 331

This is a modified version of kennebec's/Pravens code which finds the highest z-index within a stacking context. This version also takes opacity into account.

If all you're looking for is to position an element on top of everything else in the page, simply call highZ(document.body) or just highZ(). It finds the highest z-index of the root stacking context which will do exactly that.

  • Only non-statically positioned elements matter within a stacking context.
  • Elements that are not positioned do not start a new stacking context. So their descendents may exist in the current stacking context. Hence the recursion.
  • Also, if the z-index is 'auto', the element does not start a new stacking context, so you must recurse through its elements.
  • elements with an opacity value less than 1 start a new stacking context. If an element with opacity less than 1 is not positioned, implementations must paint the layer it creates, within its parent stacking context, at the same stacking order that would be used if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’. If an element with opacity less than 1 is positioned, the ‘z-index’ property applies as described in [CSS21], except that ‘auto’ is treated as ‘0’ since a new stacking context is always created.

    function highZ(parent, limit){
        limit = limit || Infinity;
        parent = parent || document.body;
        var who, temp, max= 1, opacity, i= 0;
        var children = parent.childNodes, length = children.length;
        while(i<length){
            who = children[i++];
            if (who.nodeType != 1) continue; // element nodes only
            opacity = deepCss(who,"opacity");
            if (deepCss(who,"position") !== "static") {
                temp = deepCss(who,"z-index");
                if (temp == "auto") { // positioned and z-index is auto, a new stacking context for opacity < 0. Further When zindex is auto ,it shall be treated as zindex = 0 within stacking context.
                    (opacity < 1)? temp=0:temp = highZ(who);
                } else {
                    temp = parseInt(temp, 10) || 0;
                }
            } else { // non-positioned element, a new stacking context for opacity < 1 and zindex shall be treated as if 0
                (opacity < 1)? temp=0:temp = highZ(who);
            }
            if (temp > max && temp <= limit) max = temp;                
        }
        return max;
    }
    
    function deepCss(who, css) {
        var sty, val, dv= document.defaultView || window;
        if (who.nodeType == 1) {
            sty = css.replace(/\-([a-z])/g, function(a, b){
                return b.toUpperCase();
            });
            val = who.style[sty];
            if (!val) {
                if(who.currentStyle) val= who.currentStyle[sty];
                else if (dv.getComputedStyle) {
                    val= dv.getComputedStyle(who,"").getPropertyValue(css);
                }
            }
        }
        return val || "";
    }
    

Upvotes: 4

kennebec
kennebec

Reputation: 104800

You only need sibling elements to find the highest z-index, so start with a parent element or the body.

And often you have some element with a really high z-index that you want to be always on top- if so, ignore z indexes over a million or whatever is safely above the number of siblings.

You can do it in one function, but the syntax for finding stylesheet values is handy to have around.

function highZ(pa, limit){
    limit= limit || Infinity;
    pa= pa || document.body;
    var who, tem, mx= 1, A= [], i= 0, L;
    pa= pa.childNodes, L= pa.length;
    while(i<L){
        who= pa[i++]
        if(who.nodeType== 1){
            tem= parseInt(deepCss(who,"z-index")) || 0;
            if(tem> mx && tem<=limit) mx= tem;
        }
    }
    return mx;
}
function deepCss(who, css){
    var sty, val, dv= document.defaultView || window;
    if(who.nodeType== 1){
        sty= css.replace(/\-([a-z])/g, function(a, b){
            return b.toUpperCase();
        });
        val= who.style[sty];
        if(!val){
            if(who.currentStyle) val= who.currentStyle[sty];
            else if(dv.getComputedStyle){
                val= dv.getComputedStyle(who,"").getPropertyValue(css);
            }
        }
    }
    return val || "";
}

alert(highZ())

Upvotes: 2

Kai
Kai

Reputation: 9308

meder makes a great point! I tried to code it anyway, because I'm bored at work and can't help myself:

NOTE: Will only work on style set using the style attribute (won't capture style set by stylesheets)

function getHighIndex (selector) {
    if (!selector) { selector = "*" };

    var elements = document.querySelectorAll(selector) ||
                   oXmlDom.documentElement.selectNodes(selector),
        i = 0,
        e, s,
        max = elements.length,
        found = [];

    for (; i < max; i += 1) {
        e = elements[i].style.zIndex;
        s = elements[i].style.position;
        if (e && s !== "static") {
          found.push(parseInt(e, 10));
        }
    }

    return found.length ? Math.max.apply(null, found) : 0;
}

Upvotes: -4

Charles Boyung
Charles Boyung

Reputation: 2481

You would need to loop through every single element in the DOM and keep track of the max z-index found as you loop, along with the element that has that z-index. Then, when you are done, you will have the element you are looking for.

This is an incredibly intensive piece of script and could kill your users' browsers. Why in the world would you want to do this?

Upvotes: 2

meder omuraliev
meder omuraliev

Reputation: 186662

It's not as simple as finding the element with the highest z-index. Stacking order also depends on tree relationship, so if a static positioned element with the most z-index explicitly set, and if your code retrieved that, it would be useless since z-index is useless on static positioned elements.

In addition, IE's stacking order rules are completely broken so you would have to account for that as well. And you may have to account for iframe/select elements in IE pre 8/9 since they have more stacking order priority than any other nodes.

This would probably be useful: http://www.w3.org/TR/CSS21/zindex.html

You'd have to follow all of those and account for IE bugs in order to have a consistent method of getting the element with the most stacking order priority.

Upvotes: 16

Related Questions