16
Given two arbitrary HTML elements A and B on the same page, how can I find out which one is "closest" to the user (i.e. if they overlapped, which one would obscure the other)?
To css specification of W3C describes "stacking contexts" (Stacking contexts), that the Engines of rendering that follow the standards must implement. However, I could not find a way to access this information via Javascript. All I have access to is the css property z-index
, which in itself does not say much, since in most cases it is as auto
and - even when expressed by a number - is not a reliable indicator of how elements are actually displayed (because if they belong to different stacking contexts, comparing z-indices is irrelevant).
Note: I am interested in elements arbitrary; if both are under the mouse pointer, only one will be considered "hovered", so that determining the nearest one is trivial. Similarly, if I know that they intersect at a specific point, I can use document.elementFromPoint()
as suggested in that reply in the English SO. However, it may not be the case that I know a point like this, or even exist - the elements may not intersect with each other.
There is some general solution to this problem, preferably one that does not involve reimplementing the stacking algorithm that the engine rendering is already doing anyway?
Motivation: there is a limitation on "drag-and-drop" (drag-and-drop) jQuery, where it is not possible to decide for sure where to drop a dragged element:
Older versions of jQuery would choose one of them kind of at random, while recent versions perform the drop in both (more details on that failed attempt at response). The ideal would be to choose only one of them - the one that is "closest to the screen"* - and do the drop only in it, and for that I need a correct means of determining your real z-index (even if it involves "re-inventing the wheel", as long as the result is consistent with the stacking carried out by browser).
*Another option, as pointed out by @utluiz, would be to take intersection area taken into account when determining the correct target - is by requiring that the helper is fully contained in the target, either by choosing the target with the largest intersection area (for example, if it is visually clear which is the correct target, but a "dot" of the helper plays a distinct element). But unfortunately, even to correctly calculate this area of intersection it is necessary to know the relative z indices, because it changes if one obscures the other.
Updating: a complete seemingly basant solution was posted on Soen, the full code is on Github and there’s a example of use in jsFiddle. At first glance it seems ok, but any additional feedback would be very welcome. If everything is correct, then put here as a response.
I’ve asked myself that many times and never found a solution that didn’t involve reimplementing the algorithm described in the CSS specification - which would be quite heavy.
– bfavaretto
I don’t know if it’ll do any good, but try to catch the
z-index
withwindow.getComputedStyle( elemento ).getPropertyValue("z-index")
– BrunoLM