부모 컨테이너와 관련된 요소의 위치 / 오프셋을 얻습니까?


125

나는 jQuery로 작업하는 데 익숙합니다. 그러나 현재 프로젝트에서는 zepto.js를 사용합니다. Zepto는 position()jQuery와 같은 방법을 제공하지 않습니다 . Zepto는 offset().

순수한 js 또는 Zepto를 사용하여 부모와 관련된 컨테이너의 오프셋을 검색하는 방법은 무엇입니까?


4
JavaScript 질문을 할 때 jQuery 답변 (jQuery로 레이블이 지정되지도 않음)을 수락하는 다운 투표.
John

@John zepto 태그를 보셨나요?
Supersharp

@Supersharp JavaScript순수 자바 스크립트를 사용할 때 태그를 사용하세요 . 프레임 워크 또는 라이브러리를 사용하는 경우 태그를 사용 하지 않습니다JavaScript . 이름이 Jeff라면 Sally라고 부르지 않겠습니다.
John

@John 그것은 의견이지만 어떻게 작동하는지는 아닙니다. 자바 스크립트 태그 가이드를 읽어보세요. 이 경우 라이브러리 태그와 함께 사용해야합니다.
Supersharp

@Supersharp 그래 SO는 그렇게 무능합니다. 리터럴 태그 인플레이션. 😒︎
John

답변:


188

경고 : 표준 JavaScript가 아닌 jQuery

element.offsetLeftelement.offsetTop대한 요소의 위치를 ​​찾기위한 순수한 자바 스크립트 속성입니다 offsetParent. relative또는 위치가있는 가장 가까운 상위 요소absolute

또는 항상 Zepto 를 사용 하여 요소와 상위 요소의 위치를 ​​가져오고 간단히 둘을 뺄 수 있습니다.

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

이것은 부모가 위치하지 않더라도 부모와 관련된 자식의 오프셋을 제공하는 이점이 있습니다.


9
요소의 위치 static는 오프셋 부모가 아닙니다.
Esailija 2012

5
괄호를 사용 쉼표 내부에 세미콜론을 사용하지 않는
루카 Borrione

1
고정 위치는 어떻습니까? 상쇄 된 부모입니까?
Ayyash

1
예, @ Ayya- position fixed도 새 오프셋 컨텍스트를 생성합니다
mmmeff

9
@vsync jQuery는 2016 년 1 월에 ie9가 EOL에 도달 한 이후로 무엇보다도 왕이 아닙니다. 우리는 모든 주요 브라우저에서 표준화 된 DOM 선택을 가지고 있으며 순수한 js를 배웁니다. 또한 어떤 프레임 워크를 사용할 것인지에 대한 의견은 프로젝트와 대상 플랫폼에 크게 의존하기 때문에 SO에 영향을 미치지 않습니다.
Hans Koch

72

순수 js에서는 사용 offsetLeftoffsetTop속성 만 있습니다 .
바이올린 예 : 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 요소에 대한 오프셋을 얻는 방법도 있습니까?
matt

2
p.offsetTop + p.parentNode.offsetTop몇 년 전에 제안한 PPK와 매우 유사한 재귀 함수 호출로 이것을 래핑 할 수 있습니다. 위로 올라갈 레벨 수를 전달하거나 선택기를 사용하여을 모방하도록 함수를 변경할 수 있습니다 $(selector).parents(parentSelector). zepto 구현은 getBoundingClientsRect일부 모바일에서는 지원 하지 않는 브라우저에서만 작동하기 때문에이 솔루션을 선호합니다 .
Torsten Walter

나는 getBoundingClientsRect널리 지원 되었다고 생각했습니다 ... 어떤 모바일이 지원하지 않는지 아는 사람이 있다면 관심이있을 것입니다 (모바일에 대한 지원 테이블을 찾을 수 없습니다).
Nobita

표시되지 않은 경우에도 아마도 가장 정답 일 것입니다. 내 개인적인 솔루션은 변화되었다 $(this).offset().leftthis.offsetLeft.
adjwilli

이것은 또한 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에 포함되지 않았습니다.
데이비드 스펙터

@DavidSpector 단어

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));

참고 : 당신이 사용할 수있는 마우스 클릭 또는 마우스 오버 이벤트에

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

스크롤링이 설명되지 않습니다. 발생할 수있는 이상한 경우가 많이 있습니다.
David Spector

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.