注: 1年以上回答がなかった後、この質問はポルトガル語のStack Overflowにも投稿され、決定的な解決策はありませんでしたが、一部のユーザーと私はJavaScriptでスタックメカニズムを複製できました(車輪の再発明ですが、それでも)。 ..)
CSS2仕様でのスタッキングコンテキストアルゴリズムの引用(私の強調):
ルート要素は、ルートスタッキングコンテキストを形成します。他のスタッキングコンテキストは、「auto」以外の「z-index」の計算値を持つ任意の配置された要素(比較的配置された要素を含む)によって生成されます。スタッキングコンテキストは、必ずしもブロックの包含に関連しているわけではありません。CSSの将来のレベルでは、他のプロパティがスタッキングコンテキストを導入する可能性があります(例:「不透明度」)
その説明から、以下を返す関数がありz-index
ます。a)新しいスタッキングコンテックスを生成する場合の要素の。または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);
}
これにより、さまざまなスタッキングコンテキストを形成する要素を区別できるはずです。残りの要素(および等しい要素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);
}
これらの2つの関数を定義すると、最終的に要素比較関数を作成できます。
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;
}
この方法を実際に示す3つの例を次に示します。例1、例2、例3(申し訳ありませんが、すべてを英語に翻訳する必要はありませんでした。まったく同じコードで、関数と変数の名前が異なります)。
この解決策はおそらく不完全であり、エッジケースでは失敗するはずです(私は自分自身を見つけることができませんでしたが)。誰かが改善のための提案があれば、それは本当にありがたいです。