注意:经过一年多没有答案的情况,这个问题也在葡萄牙的Stack Overflow上发布,虽然仍然没有一个确定的解决方案,但一些用户和我能够在JavaScript中复制堆叠机制(重新发明轮子,但仍然……)
引用CSS2规范中的堆叠上下文算法(强调是我的):
根元素形成根堆叠上下文。其他堆叠上下文由任何定位元素(包括相对定位元素)具有计算值为“z-index”的值而不是“auto”。堆叠上下文不一定与包含块相关。在CSS的未来级别中,其他属性可能会引入堆叠上下文,例如'opacity'
根据这个描述,以下是一个函数的返回值: 如果一个元素生成了新的堆叠上下文,则返回该元素的 z-index
;如果没有生成,则返回 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)
return +css(ctx, 'z-index');
}
function css(el, prop) {
return window.getComputedStyle(el).getPropertyValue(prop);
}
这应该能够区分形成不同堆叠上下文的元素。对于其余的元素(以及具有相等 z-index
的元素),附录 E 表示它们应该遵循“树顺序”:
在考虑移动框的属性后,按逻辑(而非视觉)顺序对呈现树进行先序深度优先遍历,对于双向内容。
除了那些“移动框的属性”之外,此函数应正确实现遍历:
function relativePosition(ctxA, ctxB, a, b) {
if ( $.inArray(b, $(a).parents()) >= 0 )
return a;
if ( $.inArray(a, $(b).parents()) >= 0 )
return b;
return ($(ctxA).index() - $(ctxB).index() > 0 ? a : b);
}
有了这两个函数的定义,我们终于可以创建我们的元素比较函数了:
function inFront(a, b) {
var pa = $(a).parents(), ia = pa.length;
var pb = $(b).parents(), ib = pb.length;
while ( ia >= 0 && ib >= 0 && pa[--ia] == pb[--ib] ) { }
var ctxA = (ia >= 0 ? pa[ia] : a), za = zIndex(ctxA);
var ctxB = (ib >= 0 ? pb[ib] : b), zb = zIndex(ctxB);
var relative = relativePosition(ctxA, ctxB, a, b);
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);
}
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(抱歉,没有将所有内容翻译成英语...它们是完全相同的代码,只是不同的函数和变量名称)。
这个解决方案很可能不完整,在边缘情况下可能会失败(尽管我自己找不到任何问题)。如果有人对改进有任何建议,那将非常感激。