1

Say I have two boxes overlapping (fiddle)

<html>
<body>
    <div class="box">element 1</div>
    <div class="box" style="left: 20px; top: 10px; background-color: red;">element 2</div>
    <style>
      .box {
        background-color: green;
        position: absolute;
        width: 100px;
        height: 100px;
        border: 1px sold red;
      }
    </style>
</body>
</html>

Is there a way to tell which box is above the other in vanilla javascript? I only care about what the user visually perceives as above.

Something like below

isAbove(el1, el2) // false
isAbove(el2, el1) // true
Pithikos
  • 18,827
  • 15
  • 113
  • 136
  • Above means what? Higher z-index? – epascarello Feb 22 '19 at 19:28
  • @epascarello it means visually being above another. The question is how to check that. Checking by z-index doesn't work in the example above. – Pithikos Feb 22 '19 at 22:08
  • I know, your question was unclear hence why it did not get attention in the last 6 hours. The deleted answer thought it meant x, y position. – epascarello Feb 22 '19 at 22:12
  • conceptually, you'd want to find their first common parent and then determine which comes first by declaration – derelict Feb 22 '19 at 22:15
  • Note, `heght` should be `height` at CSS at question and linked jsfiddle – guest271314 Feb 23 '19 at 00:23
  • It seems to me that your view is driving your model. Unless you're trying to inject something into a page over which you have no control, I can't see why you'd need to know this. – spender Feb 23 '19 at 23:11

2 Answers2

0

about the only way i can think of to tell is to get the dom paths of the elements involved and check which one comes first by declaration; this should give you an idea in the absence of z-index which element would naturally be shown 'on top' of the other.

function getAncestors(ele) {
  var ancestors = [ele];
  while(ele.parentElement) { // walk all parents and get ancestor list
    ele = ele.parentElement;
    ancestors.push(ele);
  }
  return ancestors.reverse(); // flip list so it starts with root
}

function declaredBefore(ele1,ele2) {
  var a1 = getAncestors(ele1);
  var a2 = getAncestors(ele2);
  for(var i=0;i<a1.length;i++) { // check path, starting from root
     if(a1[i] !== a2[i]) { // at first divergent path
        var testNodes = a1[i-1].childNodes; // get children of common ancestor
        for(var j=0;j<testNodes.length;j++) { // check them for first disparate ancestor
            if(testNodes[j] === a1[i]) { return true; } // ele1 is first
            if(testNodes[j] === a2[i]) { return false; } // ele2 is first
        }
     }
  }
  return undefined; // could not determine who was first
}

function isAbove(ele1, ele2) {
  // rudimentary z-index check for eles sharing a parent 
  if(ele1.parentNode === ele2.parentNode) {
    var z1 = ele1.style.zIndex;
    var z2 = ele2.style.zIndex;
    if(z1 !== undefined && z2 !== undefined) { // if both have z-index, test that
      return z1 > z2;
    }
  }
  return declaredBefore(ele2, ele1); // if 2 is declared before 1, 1 is on top
}

this solution is far from bulletproof, but it should at least let you know which element is declared last, accounting for dom tree hierarchy. it also does not compare zIndex unless the elements share a parent, although you could probably modify that to check zIndex hierarchy of parents as well.

derelict
  • 2,044
  • 10
  • 15
  • This assumes though that an element following another, is rendered first. Is this how all browsers act? – Pithikos Feb 23 '19 at 23:55
  • whatever appears last in document order is rendered on top; in the absence of z-index, elements are in z-order based on their document tree position, respecting heirarchy. you can get around this with css (flexbox is a good example, you can change the item order which presumably change the internal z-order). my example tests whichever is declared _last_, which should by default be 'on top' in terms of rendering. – derelict Feb 24 '19 at 00:03
0

Simply get those elements zIndex and compare them