Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine absolute or global z-index?

OK guys, here's a tricky one (perhaps): is there any to get a sort of "global z-index" of an element? here is an example of what i'd like to do:

given two element references, how would you determine which one is higher in the z order (given that they may not have assigned z-indices or are in separated containers)

Elaborate hacks welcome! Not-so elaborate methods more than welcome.

like image 232
Trass Vasston Avatar asked May 08 '11 20:05

Trass Vasston


People also ask

Is Z-Index Global?

z-index values are not global. By default, a plain HTML document will have a single stacking context that encompasses all nodes.

Is Z-Index absolute or relative?

z-index is relative.

Is Z-Index absolute?

An element with greater stack order is always in front of an element with a lower stack order. Note: z-index only works on positioned elements (position: absolute, position: relative, position: fixed, or position: sticky) and flex items (elements that are direct children of display:flex elements).

How do you find the Z-index without absolute positioning?

Yes: use position:relative; z-index:10 . z-index has no effect for position:static (the default).


1 Answers

This was an interesting problem. The following code may not be bug free. I just put it together right now and haven't tested it entirely. Its purpose is to demonstrate an approach.

It compares two elements and tests them on three criteria:

  • Looking through the ancestor tree of each element, if the first ancestor for element A to have a z-index has a greater z-index than the first ancestor of element B to have a z-index (if one exists for element B at all), then element A is higher in the z-order.

  • Otherwise, if element B is a descendent of element A then element B has a higher z-order.

  • Otherwise, looking at the siblings of the last ancestor that element A and element B had in common, if an ancestor of element A comes first in the array of children of that common ancestor then element B has a higher z order.

There may be an simpler way of describing of the logic above and the algorithm can be improved. (For example, the second check above could be done first.) However, here's the code:

<html>
<head>
<script language="javascript">

function getAncestorsAsArray(element){
    var arr = new Array();
    arr.unshift(element);
    while (arr[0].parentNode){
        arr.unshift(arr[0].parentNode);
    }

    return arr;
}

function highestInitialZIndex(elementArr){
    for (var i=0; i<elementArr.length; i++){
        if (elementArr[i].style == undefined) continue;
        var r = elementArr[i].style.zIndex;
        if (!isNaN(r) && r!="") {
            return r;
        }
    }

    return undefined;
}

function findCommonAncestor(elementArr1, elementArr2){
    var commonAncestor;
    for (var i=0; i<elementArr1.length; i++){
        if (elementArr1[i] == elementArr2[i]) {
            commonAncestor = elementArr1[i];
        }
    }

    return commonAncestor;
}

function findHighestAbsoluteIndex(element1, element2){
    var arr1 = getAncestorsAsArray(element1);
    var arr2 = getAncestorsAsArray(element2);

    // Does an ancestor of one elment simply have a higher z-index?
    var arr1Z = highestInitialZIndex(arr1);
    var arr2Z = highestInitialZIndex(arr2);
    if (arr1Z > arr2Z || (!isNaN(arr1Z) && isNaN(arr2Z))) return element1;
    if (arr2Z > arr1Z || (!isNaN(arr2Z) && isNaN(arr1Z))) return element2;

    // Is one element a descendent of the other?
    var commonAncestor = findCommonAncestor(arr1, arr2);
    if (commonAncestor == element1) return element2;
    if (commonAncestor == element2) return element1;

    // OK, which has the oldest common sibling? (Greater index of child node for an element = "older" child)
    var indexOfCommonAncestor;
    for (var i=0; i<arr1.length; i++){
        if (arr1[i] == commonAncestor) {
            indexOfCommonAncestor = i;
            break;
        }
    }

    for (var j=commonAncestor.childNodes.length; j>=0; j--){
        if (arr1[indexOfCommonAncestor+1] == commonAncestor.childNodes[j]) return element1;
        if (arr2[indexOfCommonAncestor+1] == commonAncestor.childNodes[j]) return element2;
    }   
}

function doTest(){
    var e1 = document.getElementById("myDiv1");
    var e2 = document.getElementById("myDiv2");

    highest = findHighestAbsoluteIndex(e1, e2);
    alert(highest.id);
}

</script>

</head>
<body onload="javascript:doTest();">

<div>
<div>
<div style="position:absolute; z-index:20;" id="myDiv1">
</div>
</div>
</div>

<div>
</div>

<div style="position:absolute; z-index:10;" id="myDiv2">
</div>

</body>
</html>

Play around with the nested divs in the body to test it working.

like image 150
Oliver Moran Avatar answered Sep 30 '22 17:09

Oliver Moran