10

if i have 2 divs (z index is not assigned), one layered over the over, can i use the reference to the top div to find which div is below it?

as far as the DOM structure goes, these two divs would be siblings. but visually they are stacked on one another.

here's an example:

<body>
<div id="box1" style="background:#e0e0e0;height:100px;width:100px;"></div>
<div id="box2" style="background:#000000;height:100px;width:100px;margin-top:-50px;"></div>
</body>

which results in this: enter image description here

so i'm trying to figure out, when having the black div, box2, a way to return box1 in jquery (using selectors), because box1 is beneath box2, using jquery.

tipu
  • 9,464
  • 15
  • 65
  • 98
  • Can you rephrase please? What do you mean return box1? Modify it, access the element, remove it? Maybe you meant that box1 is above box2 which means you can access the div like this ... http://api.jquery.com/prev/ – Tim Joyce Apr 08 '11 at 18:07
  • @Tim: I think he means: "What is a jQuery selector that will select elements covered by other elements?" – gen_Eric Apr 08 '11 at 18:09
  • Even though you are not assigning a z-index, one automatically gets assigned anyways. http://stackoverflow.com/questions/1118198/how-can-you-figure-out-the-highest-z-index-in-your-document – g19fanatic Apr 08 '11 at 18:16
  • @tipu check out my answer. It should definitely get you to where you want to be to see if the element is actually on top of or shares another elements x/y coordinates – hunter Apr 08 '11 at 18:33
  • @tipu Some time ago, I've written a overlapping-detection script. See here: http://vidasp.net/tinydemos/javascript-detect-overlapping.html – Šime Vidas Apr 08 '11 at 18:48

5 Answers5

23

Check if box1 is sharing the same position as a certain spot on the page.


And only because I'm a little bored, I made this awesome-er

http://jsfiddle.net/hunter/PBAb6/

function GetAllElementsAt(x, y) {
    var $elements = $("body *").map(function() {
        var $this = $(this);
        var offset = $this.offset();
        var l = offset.left;
        var t = offset.top;
        var h = $this.height();
        var w = $this.width();

        var maxx = l + w;
        var maxy = t + h;

        return (y <= maxy && y >= t) && (x <= maxx && x >= l) ? $this : null;
    });

    return $elements;
}
hunter
  • 62,308
  • 19
  • 113
  • 113
  • Maybe I'm missing something, but it doesn't seem to work: http://jsfiddle.net/8zetz/3/ Returns true even when boxes don't overlap. – Adam Terlson Apr 08 '11 at 18:34
  • it returns `true` if `box1` is at the position based on its offset and height/width, regardless of whatever is on top of it. – hunter Apr 08 '11 at 18:37
  • 1
    this was a bit buggy, fixed. Works well – hunter Apr 08 '11 at 19:33
  • 1
    Jeesh. You got a little carried away. Have an upvote for your troubles. – Adam Terlson Apr 08 '11 at 19:39
  • @Adam - Yeah... thought I would figure out how to do this. This would make a nice jQuery extension to find all elements at a given point, but it could probably use some optimizing since it's selecting `body *` which I'm guessing is a heavy operation. – hunter Apr 08 '11 at 19:51
  • WOW that is a very expensive operation calculating height, width, offset of EVERY element. In limited cases that may work though. – NoBugs Jan 18 '17 at 18:32
  • 1
    YOURE A BOSSSSSSS! Cool script. – Andy Apr 25 '17 at 04:18
  • 1
    I've modified and employed on a browser MMO, come see your work! www.StarCommanderOnline.com – Andy Apr 25 '17 at 04:28
  • What about z-index? – Sebastianb Jan 24 '19 at 15:14
  • I've made a new function based on this one, it allows to specify css celectors and set an offset around the specified point, see https://stackoverflow.com/a/70588539/8646418 – Artem Jan 05 '22 at 06:27
3

Maybe something along these lines... detach the element under your cursor (in this case box1) and use document.elementFromPoint to fetch the next element underneath that x,y position.. rough example:

    var first_box = $('#box1');// more programmaticaly would be to use document.elementFromPoint to fetch the element under your cursor

    var first_box_offset = first_box.offset();
    var x = first_box_offset.left;
    var y= first_box_offset.top + first_box.height();

    var reattach_me = first_box.detach();
    var second_box = document.elementFromPoint(x, y);

    $('body').append(reattach_me);
Jake
  • 2,471
  • 15
  • 24
0

As far as I know, there isn't a selector for this. You could probably write a function to do this though. I would iterate over each element that precedes the div in question and check whether or not it's bounding box is in the desired div.

Aaron Hathaway
  • 4,280
  • 2
  • 19
  • 17
0

The only way, as you have it in the sample case, to actually have another DIV layering over another is if it comes after it in the DOM. So, your simple answer is that any div is over another div if it comes after it in the DOM tree. Please provide a more illustrative example if this is insufficient.

You can illustrate that this works by attempting to add a positive margin to DIV1. You'll note that it kicks DIV2 downward. DIV2, however, when given a negative margin will "layer" over DIV1. In your scenario using margins and divs without z-index or other positioning methods, it's not possible for DIV1 to overlap DIV2.

EDIT based on comments:

The process of figuring out if two elements occupy the same space is a different game. A general run down of your method would be to get the coordinate position for your anchor and get its width and height as well. Then, loop through all the divs and see if the anchor's position overlaps any of their coordinates. If it overlaps multiple divs, take the one last in the DOM as it'll be on top of the other.

Please don't make me write a code sample. :)

Adam Terlson
  • 12,610
  • 4
  • 42
  • 63
  • this is true. in my use case however, i am using a jquery slider whose position in the dom tree isn't as useful because as it animates, it crosses through 4 other div elements that i need to be checking for. so 5 elements are siblings, its: a div div div div div. the a element is being animated with jquery slider. – tipu Apr 08 '11 at 18:20
  • So you're trying to figure out what exactly? If the anchor is over one of the divs? – Adam Terlson Apr 08 '11 at 18:22
0

I re-made the accepted answer by @hunter:

function getCertainElementsAt(selectors, x, y, around) {

    //selector variants: 'all' / '.selector' / ['.class','#id','[attribute="whatever"]', 'etc']
    if(Array.isArray(selectors)){
        selectors = 'body ' + selectors.join(', body ');
    } else {
        selectors = selectors === 'all' ? 'body *' : 'body ' + selectors;
    }

    let $around =  typeof around === 'undefined' ? 0 : parseInt(around);

    return $(selectors).map(function() {

        let $this = $(this);
        let offset = $this.offset();
        let l = offset.left;
        let t = offset.top;
        let h = $this.outerHeight();
        let w = $this.outerWidth();

        let Xmin = l - $around;
        let Xmax = l + w + $around;

        let Ymin = t - $around;
        let Ymax = t + h + $around;

        return (Xmin <= x && x <= Xmax) && (Ymin <= y && y <= Ymax) ? $this : null;
    });
}

What's new:

  • Unnecesary #elements variable has been removed
  • vars have been replaced with lets
  • Replaced width() and height() with outerWidth() and outerHeight()
  • The function accepts the selectors argument (possible values: 'all', a 'string' with a selector, an array of strings with selectors, see the example in the code)
  • The function accepts the around argument (a number of pixels around your specified point), which allows you to find adjacent elements.
  • Also, I made the final condition a little more readable
Artem
  • 81
  • 6