親コンテナに対する要素の位置/オフセットを取得しますか?


125

私はjQueryでの作業に慣れています。現在のプロジェクトでは、zepto.jsを使用しています。Zeptoはposition()jQueryが提供するようなメソッドを提供しません。Zeptoにのみ付属offset()ます。

純粋なjsまたはZeptoを使用して、親を基準にしたコンテナのオフセットを取得する方法はありますか?


4
JavaScriptの質問をするときに、jQueryの回答(jQueryとしてラベル付けさえされていない!)を受け入れることに反対票を投じました。
ジョン

@Johnはzeptoタグに気付きましたか?
Supersharp

@Supersharp JavaScript純粋なJavaScriptを使用しているときにタグを使用します。フレームワークまたはライブラリを使用している場合は、タグを使用しませJavaScript。あなたの名前がジェフである場合、私はあなたをサリーと呼ぶことはありません。
ジョン

@Johnそれは意見ですが、SOの動作方法ではありません。JavaScriptタグガイドをお読みください。この場合、ライブラリタグと一緒に使用する必要があります。
Supersharp

@SupersharpそうそうSOはそのような無能です。リテラルタグインフレーション。😒︎
ジョン

回答:


188

警告:標準JavaScriptではなくjQuery

element.offsetLeftそしてelement.offsetTopそのに対する要素の位置を見つけるために純粋なJavaScriptの特性ですoffsetParentrelativeまたはの位置を持つ最も近い親要素であることabsolute

または、常にZeptoを使用して要素とその親の位置を取得し、単純に2つを減算することもできます。

var childPos = obj.offset();
var parentPos = obj.parent().offset();
var childOffset = {
    top: childPos.top - parentPos.top,
    left: childPos.left - parentPos.left
}

これには、親が配置されていない場合でも、親に対する子のオフセットを与えるという利点があります。


9
要素の配置staticはオフセットされた親ではありません。
エサイリャ

5
ブレースの内側にセミコロンを使用しないでください。カンマを使用してください
Luca Borrione 2013年

1
固定位置はどうですか?彼らは両親を相殺していますか?
Ayyash 14

1
はい、@ Ayya-位置が固定されていると、新しいオフセットコンテキストも作成されます
mmmeff

9
@vsync jQueryは、ie9が2016年1月にEOLに達して以来、何よりも重要ではありません。すべての主要なブラウザーで標準化されたDOMの選択があります。純粋なjsを学んでください。また、どのフレームワークを使用するかについての意見は、プロジェクトとターゲットプラットフォームに大きく依存するため、SOには意味がありません。
Hans Koch

72

純粋なJSにだけ使用offsetLeftしてoffsetTopプロパティ。
フィドルの例:http : //jsfiddle.net/WKZ8P/

var elm = document.querySelector('span');
console.log(elm.offsetLeft, elm.offsetTop);
p   { position:relative; left:10px; top:85px; border:1px solid blue; }
span{ position:relative; left:30px; top:35px; border:1px solid red; }
<p>
    <span>paragraph</span>
</p>


ありがとうございました。parent.parent要素へのオフセットを取得する方法もありますか?
マット

2
p.offsetTop + p.parentNode.offsetTopこれは、PPKが数年前に提案しように、再帰的な関数呼び出しでラップできます。レベル数を上げて上に行くように関数を変更するか、セレクターを使用して模倣することができ$(selector).parents(parentSelector)ます。Zeptoの実装は、getBoundingClientsRect一部のモバイルではサポートされていないブラウザーをサポートするブラウザーでのみ機能するため、このソリューションを選択します。
Torsten Walter

getBoundingClientsRectは広くサポートされていると思いました...誰もがそれをサポートしていないモバイルを知っているなら、私は興味があります(それについてのモバイルのサポート表が見つかりません)。
のび太

マークされていなくても、これがおそらく最も正しい答えです。私の個人的な解決策はに変わり$(this).offset().leftましたthis.offsetLeft
adjwilli 14

これjQuery.position()により、3D変換された親内での誤った動作も修正されます。ありがとうございました。
rassoh

6

Internet Explorerでこのようにしました。

function getWindowRelativeOffset(parentWindow, elem) {
    var offset = {
        left : 0,
        top : 0
    };
    // relative to the target field's document
    offset.left = elem.getBoundingClientRect().left;
    offset.top = elem.getBoundingClientRect().top;
    // now we will calculate according to the current document, this current
    // document might be same as the document of target field or it may be
    // parent of the document of the target field
    var childWindow = elem.document.frames.window;
    while (childWindow != parentWindow) {
        offset.left = offset.left + childWindow.frameElement.getBoundingClientRect().left;
        offset.top = offset.top + childWindow.frameElement.getBoundingClientRect().top;
        childWindow = childWindow.parent;
    }

    return offset;
};

===================このように呼び出すことができます

getWindowRelativeOffset(top, inputElement);

私は私の焦点に従ってのみIEに焦点を当てていますが、他のブラウザーでも同様のことができます。


1

イベントのオフセットを親要素のオフセットに追加して、イベントの絶対オフセット位置を取得します。

例 :

HTMLElement.addEventListener('mousedown',function(e){

    var offsetX = e.offsetX;
    var offsetY = e.offsetY;

    if( e.target != this ){ // 'this' is our HTMLElement

        offsetX = e.target.offsetLeft + e.offsetX;
        offsetY = e.target.offsetTop + e.offsetY;

    }
}

イベントターゲットがイベントが登録された要素でない場合、「絶対」オフセット値を計算するために、現在のイベントオフセットに親のオフセットが追加されます。

Mozilla Web APIによれば、「HTMLElement.offsetLeft読み取り専用プロパティは、現在の要素の左上隅がHTMLElement.offsetParentノード内で左にオフセットされているピクセル数を返します。

これは主に、たとえば、内部アイコンまたはテキストスパンを持つボタン、内部スパンを持つli要素など、さらにいくつかの子を含む親にイベントを登録したときに発生します。等...


親の親はどうですか?スクロールバーを持つネストされた要素はどうですか?display:noneを持つ以前の要素はどうですか?真のドキュメントオフセット位置を計算することはほとんど不可能ですが、レンダリングエンジンはそれを知ることができます。ドキュメントの位置などのあまりにも悪い単純なプロパティは、DOMに含まれていません。
David Spector

@DavidSpector word

1

したがって、idが「child-element」の子要素があり、それを親要素に対する左/上位置にしたい場合、「item-parent」のクラスを持つdivとすると、このコードを使用します。

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position.top);

プラグイン最後に、実際のプラグインについて(何が起こっているのかを説明するいくつかのメモ付き):

// offsetRelative (or, if you prefer, positionRelative)
(function($){
    $.fn.offsetRelative = function(top){
        var $this = $(this);
        var $parent = $this.offsetParent();
        var offset = $this.position();
        if(!top) return offset; // Didn't pass a 'top' element 
        else if($parent.get(0).tagName == "BODY") return offset; // Reached top of document
        else if($(top,$parent).length) return offset; // Parent element contains the 'top' element we want the offset to be relative to 
        else if($parent[0] == $(top)[0]) return offset; // Reached the 'top' element we want the offset to be relative to 
        else { // Get parent's relative offset
            var parent_offset = $parent.offsetRelative(top);
            offset.top += parent_offset.top;
            offset.left += parent_offset.left;
            return offset;
        }
    };
    $.fn.positionRelative = function(top){
        return $(this).offsetRelative(top);
    };
}(jQuery));

注: mouseClickまたはmouseoverイベントでこれを使用できます

$(this).offsetRelative("div.item-parent");

スクロールが考慮されていないようです。起こり得る奇妙なケースがたくさんあります。
デビッドスペクター

1

私は別の解決策を得ました。子プロパティ値から親プロパティ値を減算します

$('child-div').offset().top - $('parent-div').offset().top;

0

確かに純粋なJSで簡単です。これを行うだけで、固定およびアニメーション化されたHTML 5パネルでも機能します。私はこのコードを作成して試してみれば、任意のブラウザ(IE 8を含む)で機能します。

<script type="text/javascript">
    function fGetCSSProperty(s, e) {
        try { return s.currentStyle ? s.currentStyle[e] : window.getComputedStyle(s)[e]; }
        catch (x) { return null; } 
    }
    function fGetOffSetParent(s) {
        var a = s.offsetParent || document.body;

        while (a && a.tagName && a != document.body && fGetCSSProperty(a, 'position') == 'static')
            a = a.offsetParent;
        return a;
    }
    function GetPosition(s) {
        var b = fGetOffSetParent(s);

        return { Left: (b.offsetLeft + s.offsetLeft), Top: (b.offsetTop + s.offsetTop) };
    }    
</script>

親ノードと要素プロパティのすべての可能なケースでテストしましたか?これはスクロールとネストされたスクロールを考慮していますか?
David Spector
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.