注意:在一年多没有答案之后,这个问题也被发布在 Stack Overflow 上的葡萄牙语中,并且 - 虽然仍然没有最终的解决方案 - 我和一些用户能够在 JavaScript 中复制堆栈机制(重新发明轮子,但仍然。 ..)
引用CSS2 规范中的堆叠上下文算法(强调我的):
根元素形成根堆叠上下文。其他堆叠上下文由任何具有计算值 'z-index' 的定位元素(包括相对定位的元素)生成,而不是 'auto' 。堆叠上下文不一定与包含块相关。在未来的 CSS 级别中,其他属性可能会引入堆叠上下文,例如“不透明度”
根据该描述,这是一个返回的函数: a)z-index
元素的 ,如果它生成新的堆叠上下文;或 b)undefined
如果不是>
function zIndex(ctx) {
if ( !ctx || ctx === document.body ) return;
var positioned = css(ctx, 'position') !== 'static';
var hasComputedZIndex = css(ctx, 'z-index') !== 'auto';
var notOpaque = +css(ctx, 'opacity') < 1;
if(positioned && hasComputedZIndex) // Ignoring CSS3 for now
return +css(ctx, 'z-index');
}
function css(el, prop) {
return window.getComputedStyle(el).getPropertyValue(prop);
}
这应该能够将形成不同堆叠上下文的元素分开。对于其余元素(以及具有 equal 的元素z-index
),附录 E表示它们应该尊重“树顺序”:
在考虑了移动框的属性之后,按双向内容的逻辑(非视觉)顺序对渲染树进行预排序深度优先遍历。
除了那些“移动盒子的属性”之外,这个函数应该正确地实现遍历:
/* a and b are the two elements we want to compare.
* ctxA and ctxB are the first noncommon ancestor they have (if any)
*/
function relativePosition(ctxA, ctxB, a, b) {
// If one is descendant from the other, the parent is behind (preorder)
if ( $.inArray(b, $(a).parents()) >= 0 )
return a;
if ( $.inArray(a, $(b).parents()) >= 0 )
return b;
// If two contexts are siblings, the one declared first - and all its
// descendants (depth first) - is behind
return ($(ctxA).index() - $(ctxB).index() > 0 ? a : b);
}
定义了这两个函数后,我们终于可以创建元素比较函数了:
function inFront(a, b) {
// Skip all common ancestors, since no matter its stacking context,
// it affects a and b likewise
var pa = $(a).parents(), ia = pa.length;
var pb = $(b).parents(), ib = pb.length;
while ( ia >= 0 && ib >= 0 && pa[--ia] == pb[--ib] ) { }
// Here we have the first noncommon ancestor of a and b
var ctxA = (ia >= 0 ? pa[ia] : a), za = zIndex(ctxA);
var ctxB = (ib >= 0 ? pb[ib] : b), zb = zIndex(ctxB);
// Finds the relative position between them
// (this value will only be used if neither has an explicit
// and different z-index)
var relative = relativePosition(ctxA, ctxB, a, b);
// Finds the first ancestor with defined z-index, if any
// The "shallowest" one is what matters, since it defined the most general
// stacking context (affects all the descendants)
while ( ctxA && za === undefined ) {
ctxA = ia < 0 ? null : --ia < 0 ? a : pa[ia];
za = zIndex(ctxA);
}
while ( ctxB && zb === undefined ) {
ctxB = ib < 0 ? null : --ib < 0 ? b : pb[ib];
zb = zIndex(ctxB);
}
// Compare the z-indices, if applicable; otherwise use the relative method
if ( za !== undefined ) {
if ( zb !== undefined )
return za > zb ? a : za < zb ? b : relative;
return za > 0 ? a : za < 0 ? b : relative;
}
else if ( zb !== undefined )
return zb < 0 ? a : zb > 0 ? b : relative;
else
return relative;
}
以下是三个在实践中展示此方法的示例:示例 1、示例 2、示例 3(抱歉,没有费心将所有内容翻译成英文……这是完全相同的代码,只是函数和变量名称不同)。
该解决方案很可能是不完整的,并且在极端情况下应该会失败(尽管我自己找不到)。如果有人对改进有任何建议,将不胜感激。