通过实际z-index比较HTML元素

mgi*_*nbr 10 html css z-index webpage-rendering

给定同一文档中的两个abitrary HTML元素A和B,如何找出哪个"更接近"用户(即如果它们重叠,哪一个模糊另一个)?

W3C CSS规范描述堆叠内容,这符合渲染引擎应该实现.但是,我找不到在JavaScript程序,跨浏览器中访问此信息的方法.我所能读到的只是css z-index属性,本身并没有多说,因为大部分时间都设置为auto或者,即使表示为数值,也不是它实际显示方式的可靠指标(如果它们属于对于不同的statcking上下文,比较z-index是无关紧要的).

请注意,我对任意元素感兴趣:如果两个元素都在鼠标指针下方,则只有一个被认为是"悬停",所以在这种情况下我可以轻松找到最接近的元素.但是,我正在寻找一种更通用的解决方案,最好是不涉及重新实现渲染引擎已经执行的堆叠算法的解决方案.

更新:让我澄清一下这个问题背后的原因:我最近解决了一个暴露jQuery拖放机制限制的问题 - 它在删除时不会考虑z索引,所以如果一个元素模糊了另一个,它仍然可以在"后面"的元素中执行放置操作.虽然针对OP特定案例回答了相关问题,但一般问题依然存在,而且我所知道的解决方案并不容易.

alex下面的答案很有用,但对于手头的情况还不够:拖动时,拖动的元素本身(或者更确切地说是它的帮助器)是鼠标光标下面的最顶层元素,因此elementFromPoint将返回而不是下一个最顶层的元素,我们确实需要(解决方法: 设置光标样式,使其位于助手之外).jQuery采用的其他交集策略也不仅仅考虑了一个点,这使得确定与助手交叉的最顶层元素的任务变得复杂化.能够通过实际z-index比较(或排序)元素将使得"z-index感知"交叉模式对于一般情况是可行的.

ale*_*lex 5

您可以获取元素的尺寸和偏移量,然后用于document.elementFromPoint()确定哪一个是渲染在顶部的元素。


Jip*_*Jip 1

经过几天的研究,我认为我已经根据 2016 年的规则成功地重新实现了堆叠机制。我基本上更新了 2013 年的方法(由 OP 发布)。结果是一个比较两个 DOM 节点的函数,并返回视觉上位于顶部的节点。

front = $.fn.visuallyInFront(document.documentElement, document.body);
// front == <body>...</body> because the BODY node is 'on top' of the HTML node
Run Code Online (Sandbox Code Playgroud)

推理

还有其他方法可以确定哪个元素位于另一个元素之上。例如document.elementFromPoint(),或者document.elementsFromPoint()浮现在脑海中。然而,有许多(未记录的)因素影响这些方法的可靠性。例如,不透明度、可见性、指针事件、背面可见性和某些变换可能会导致document.elementFromPoint()无法命中测试特定元素。document.elementFromPoint()然后存在只能查询最顶层元素(而不是底层元素)的问题。这个问题应该用 来解决document.elementsFromPoint(),但目前只在 Chrome 中实现。除此之外,我还向 Chrome 开发人员提交了一个关于document.elementsFromPoint(). 当对锚标记进行命中测试时,所有底层元素都不会被注意到。

所有这些问题加在一起让我决定尝试重新实现堆叠机制。这种方法的好处是,堆栈机制的记录相当广泛,并且可以测试和理解。

怎么运行的

我的方法重新实现了 HTML 堆叠机制。它旨在正确遵循影响 HTML 元素堆叠顺序的所有规则。这包括定位规则、浮动、DOM 顺序,还包括不透明度、变换等 CSS3 属性以及过滤器和遮罩等更多实验性属性。截至 2016 年 3 月,这些规则似乎已正确实施,但将来当规范和浏览器支持发生变化时,需要进行更新。

我已将所有内容放在GitHub 存储库中。希望这种方法能够继续可靠地发挥作用。以下是实际代码的JSFiddle 示例。在示例中,所有元素都按实际的“z-index”排序,这就是OP所追求的。

非常欢迎对此方法进行测试和反馈!