按实际z-index比较HTML元素 [英] Compare HTML elements by actual z-index

查看:142
本文介绍了按实际z-index比较HTML元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在同一文档中给出两个HTML元素A和B,我如何知道哪个更接近用户(即如果它们重叠,哪一个模糊了另一个)?



W3C CSS规格说明堆叠上下文,这些兼容的呈现引擎应该实现。但是,我找不到一个方法来访问这个信息在JavaScript程序,跨浏览器或不。所有我可以读的是css z-index 属性,本身并没有多说,因为大多数时间设置为 auto 或者,即使表示为数值,也不是一个可靠的指示器,如果它们属于不同的statcking上下文,比较z-index是不相关的)。



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



更新:,让我澄清一下这个问题背后的原因:我最近处理了一个问题,暴露了一个限制在jQuery的拖放机制 - 它不考虑z-index在删除时,所以如果一个元素遮蔽另一个,它仍然可以执行drop操作在后面的元素。虽然针对OP特定情况回答了链接的问题,但是一般问题仍然存在,并且没有我知道的简单解决方案。



aex's answer 下面是有用的,但是不足以处理手头的情况:拖动时,拖动的元素本身(或更确切地说,它的帮助器)是最下面的元素鼠标光标,因此 elementFromPoint 将返回而不是最顶层元素,我们真正需要的(解决方法: 为光标设置样式,以使其位于辅助程序外部)。 jQuery使用的其他交集策略也考虑了不止一个点,使确定与帮助者相交的最顶层元素的任务复杂化。能够通过实际z索引比较(或排序)元素将使得z-索引感知交叉模式对于一般情况可行。

解决方案

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

  front = $ .fn .visuallyInFront(document.documentElement,document.body); 
// front ==< body> ...< / body>因为BODY节点是HTML节点的顶部

推理



还有其他方法来确定哪个元素在另一个元素之上。例如 document.elementFromPoint() document.elementsFromPoint()然而,存在影响这些方法的可靠性的许多(未记录的)因素。例如,不透明度,可见性,指针事件,背景可见性和一些变换可能会使 document.elementFromPoint()无法命中测试特定元素。然后有一个问题, document.elementFromPoint()只能查询最顶层的元素(不是底层的)。这应该用 document.elementsFromPoint()解决,但目前只有在Chrome中实现。除此之外,我向Chrome开发者提交了一个有关 document.elementsFromPoint()的错误。当点击测试锚标签时,所有底层元素都会被忽略。



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



工作原理 p>

我的方法重新实现了HTML堆栈机制。它旨在正确地遵循影响HTML元素的堆叠顺序的所有规则。这包括定位规则,浮动,DOM顺序,但也包括CSS3属性,如透明度,变换和更多的实验属性,如过滤器和掩码。这些规则似乎在2016年3月正确实现,但是将来需要在规范和浏览器支持更改时更新。



我把所有内容放在一起在 GitHub存储库中。希望这种方法将继续可靠地工作。这里是一个示例JSFiddle 的代码在行动。在示例中,所有元素都按照实际的z-index进行排序,这是OP之后。



测试和反馈对此方法将是非常欢迎!


Given two abitrary HTML elements A and B in the same document, how can I find out which one is "closer" to the user (i.e. if they overlap, which one is obscuring the other)?

The W3C CSS Specification describes stacking contexts, which compliant rendering engines should implement. However, I couldn't find a way to access this information in a JavaScript program, cross-browsers or not. All I can read is the css z-index property, that per se doesn't say much, since most of the time is set to auto or, even when expressed as a numeric value, is not a reliable indicator of how it's actually displayed (if they belong to different statcking contexts, comparing z-indexes is irrelevant).

Please note that I'm interested in arbitrary elements: if both elements are below the mouse pointer, only one will be considered "hovered", so I can easily find the closest one in this case. However, I'm looking for a more general solution, preferably one that does not involve re-implementing the stacking algorithm that the rendering engine is already performing.

Update: let me clarify a bit the reason behind this question: I recently tackled a question that exposed a limitation in jQuery's drag and drop mechanism - it doesn't take z-indexes into account when dropping, so if an element is obscuring another, it can still perform the drop operation in the element that is "behind". While the linked question was answered for the OP particular case, the general problem persists, and there's no easy solution that I know of.

alex's answer below is useful, but not enough for the case at hand: when dragging, the dragged element itself (or more precisely its helper) is the topmost element under the mouse cursor, so elementFromPoint will return it instead of the next topmost element, that we really need (workaround: style the cursor so it's placed outside the helper). The other intersection strategies that jQuery employ also take into account more than just one point, complicating the task of determining the topmost element that intersects the helper somehow. Being able to compare (or sort) elements by actual z-index would make a "z-index aware" intersection mode viable for the general case.

解决方案

After some days of research I think I've successfully re-implemented the stacking mechanism according to the rules of 2016. I've basically updated the 2013 approach (posted by the OP). The result is a function which compares two DOM nodes, and returns the one which is visually on top.

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

Reasoning

There are other ways to determine which element is on top of the other. For example document.elementFromPoint() or document.elementsFromPoint() spring to mind. However, there are many (undocumented) factors that influence the reliability of these methods. For example, opacity, visibility, pointer-events, backface-visibility and some transforms may make document.elementFromPoint() unable to hit test a specific element. And then there is the issue that document.elementFromPoint() can only query the top-most element (not underlying ones). This should be solved with document.elementsFromPoint(), but currently has only been implemented in Chrome. In addition to that, I filed a bug with the Chrome developers about document.elementsFromPoint(). When hit testing an anchor tag, all underlying elements go unnoticed.

All these issues combined made me decide to attempt a re-implementation of the stacking mechanism. The benefit of this approach is that the stacking mechanism is documented quite extensively and that it can be tested and understood.

How it works

My approach re-implements the HTML stacking mechanism. It aims to correctly follow all the rules which influence the stacking order of HTML elements. This includes positioning rules, floats, DOM order but also CSS3 properties like opacity, transform and more experimental properties like filter and mask. The rules seem to be correctly implemented as of march 2016, but will need to be updated in the future when the specification and browser support changes.

I've put everything together in a GitHub repository. Hopefully this approach will continue to work reliably. Here is an example JSFiddle of the code in action. In the example all elements are being sorted by actual 'z-index', which is what the OP was after.

Testing and feedback on this approach would be very welcome!

这篇关于按实际z-index比较HTML元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆