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


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.offsetLeft에 element.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에서는 사용 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 요소에 대한 오프셋을 얻는 방법도 있습니까?
— matt

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

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

표시되지 않은 경우에도 아마도 가장 정답 일 것입니다. 내 개인적인 솔루션은 변화되었다 $(this).offset().left에 this.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.