3

私の問題は、次のデモhttp://jsfiddle.net/legrass/ca22L/およびhttp://jsfiddle.net/legrass/eER66/2/に関連しています。

つまり、ページ上のいくつかの要素を(たとえば、赤い境界線で)強調表示する必要がありますが、実際の要素には触れないでください(元のページのレイアウトに影響を与えないようにするため)。そのために、JSでは、要素の上に絶対的に配置された「オーバーレイ」要素を作成して、左上の座標を使用して強調表示します。これらは本文に追加され、CSSを介してスタイル設定されます(最初のJSFiddleを参照)。例えば:

<body>
<div class='overlay'>
<span class="a" style="top: 14px; left: 321px; width: 200px; height: 140px;"> </span>
<span class="b" style="top: 52px; left: 351px; width: 140px; height: 63px;"> </span>
<span class="c" style="top: 72px; left: 400px; width: 8px; height: 16px;"></span>
<span class="c" style="top: 74px; left: 420px; width: 8px; height: 16px;"></span>
</div>
....

それはうまくいきます。ただし、より柔軟なcssセレクター(子など)を使用できるようにするには、次のようにネストして上記のオーバーレイを作成する必要があります。

<body>
<div class='overlay'>
<span class="a" style="top: 14px; left: 321px; width: 200px; height: 140px;">
   <span class="b" style="top: 52px; left: 351px; width: 140px; height: 63px;">
      <span class="c" style="top: 72px; left: 400px; width: 8px; height: 16px;"></span>
      <span class="c" style="top: 74px; left: 420px; width: 8px; height: 16px;"></span>
   <span/>
<span/>
</div>
....

入れ子は任意の深さにすることができます。残念ながら、現在の位置は正しくありません(2番目のJSFiddleを参照)。

これは、各スパンが絶対的に配置されているが、その親を基準にして配置されており、単一のコンテナdivに対しては配置されていないためだと理解しています。相対測位を試しましたが、もちろん機能しません。

質問:最初のJSfiddleのようにレイアウトを取得する方法はありますが、階層全体を維持する方法はありますか?

更新 以下の回答から、offsetLeftとoffsetTopを使用して座標を調整すると非常に役立ちます。DOMを上って、offsetParentが存在するまでoffsetLeft(offsetTop)を追加する合計オフセットを計算します。ただし、結果はまだ数ピクセルシフトされており、考慮すべきことが他にあるようです。何か案が?

解決済み コメントで後述するように、境界線の幅も考慮する必要があります。

4

3 に答える 3

2

現在、CSSには、相対的または絶対的に配置された最も近い祖先を基準にする以外に要素を配置する方法がありません。ただし、JSを使用しているため、祖先要素のオフセットに応じて各要素のオフセット( 、 )を変更し、必要な結果を得ることができます。lefttop

クァークズモード機能の改良版(境界線を考慮):

function getCssPropertyValue(elem, prop) {
    return window.getComputedStyle
         // Modern browsers.
         ? window.getComputedStyle(elem, null).getPropertyValue(prop)
         // IE8 and older.
         : elem.currentStyle.getAttribute(prop);
}

function findPos(obj) {
    var curleft = curtop = 0;

    if (!obj.offsetParent) {
        return;
    }

    do {
        curleft += obj.offsetLeft;
        curtop  += obj.offsetTop;

        // If not Opera and not IE8 (see http://tanalin.com/en/articles/ie-version-js/ )
        // Opera and IE8 return incorrect values otherwise.
        if (!window.opera && (!document.all || document.addEventListener || !document.querySelector)) {
            var blw = parseInt(getCssPropertyValue(obj, 'border-left-width'), 10),
                btw = parseInt(getCssPropertyValue(obj, 'border-top-width'), 10);

            if (blw) {
                curleft += blw;
            }

            if (btw) {
                curtop += btw;
            }
        }
    }
    while (obj = obj.offsetParent);

    return [curleft, curtop];
}

更新:より明確で、コンパクトで、高速で、正確で、将来を見据えた、防弾のソリューションを使用することelement.getBoundingClientRect()です。

function getElementCoords(elem) {
    var root  = document.documentElement,
        body  = document.body,
        sTop  = window.pageYOffset || root.scrollTop  || body.scrollTop,
        sLeft = window.pageXOffset || root.scrollLeft || body.scrollLeft,
        cTop  = root.clientTop  || body.clientTop  || 0,
        cLeft = root.clientLeft || body.clientLeft || 0,
        rect  = elem.getBoundingClientRect(),
        top   = Math.round(rect.top  + sTop  - cTop),
        left  = Math.round(rect.left + sLeft - cLeft);

    return {
        top  : top,
        left : left
    };
}

ちなみに、クロスブラウザのoffset()不整合がすぐに回避されているjQueryの使用を検討してください。

于 2013-01-03T16:55:54.733 に答える
2

ボックス モデルに影響を与えることなく、アウトラインを使用して境界線を追加できます。

于 2013-01-03T16:53:27.730 に答える
0

position: absolute静的に配置されていない最初の祖先に対する要素の配置を作成します(つまり、「絶対」は実際には相対的です!)。含まれているスパンは静的に配置されていないため(絶対的に配置されています)、含まれているスパンは、ではなく、親に対して相対的に配置され.overlayます。同じ効果を得る唯一の方法は、すべての祖先の累積オフセットを考慮し、それに応じて上、左などを設定することです。

PS:長方形にスパンを使用するのは少し奇妙です。なぜなら、スパンはブロック要素ではなくインライン要素だからです。代わりにdivを使用してみませんか?結果を変更するべきではありませんが、divはあなたが使用するのに適切なもののようです。

于 2013-01-03T20:53:14.713 に答える