브라우저 창을 기준으로 HTML 요소의 위치 (X, Y)를 검색합니다


1566

브라우저 창을 기준으로 JavaScript img와 같은 HTML 요소의 X 및 Y 위치를 얻는 방법을 알고 싶습니다 div.


134
무엇에 비해?
AnthonyWJones

4
나는 (내가 문서 유형이 될 수 있습니다 ... 어떤 proboem를 가진 기억하지 않았다) ie5,6,7 불일치 모든 브라우저에서 작동 코드이 7 개 라인을 사용했다 quirksmode.org/js/findpos합니다. html 과 나는 수년 동안 그것을 많이 사용했습니다. 누군가가 결함을 지적 할 수 있습니다.
Jayapal Chandran

98
@AnthonyWJones, 나는 당신이 pedantic 즐거움을 필요로한다고 생각하지만, OP가 가장 일반적인 경우를 나타내거나 브라우저의 창 좌표를 나타내는 것이 분명합니다.
Motes

7
@Mote, 아니요, 그렇게 분명하지 않습니다. 추론, 주관성 및 허위 공리를 ​​따로 두십시오. 뷰포트 또는 페이지 상단 (일명 document.documentElement)을 기준으로 할 수 있습니다.
Andre Figueiredo

15
가장 일반적인 기본값은 추론이 아니며, 논리적 진행이므로 창을 기준으로하거나 "페이지 상단"이 사용자가 입력 한 용어 일 수 있습니다. Game Theory에서는 Schelling point라는 개념으로 체계화되어 있습니다. 가장 일반적인 경우를 의미하지 않는시기를 지정하십시오.
Motes

답변:


1795

올바른 접근 방식은 다음을 사용하는 것입니다 element.getBoundingClientRect().

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer는 관심이 있고 CSSOM보기 에서 표준화 된 이후로이를 지원했습니다 . 다른 모든 브라우저 는 오래 전에 그것을 채택했습니다 .

비표준이지만 일부 브라우저는 높이 및 너비 속성도 반환합니다. 이전 버전의 브라우저 호환성에 대해 걱정이되는 경우이 답변의 개정판에서 최적화 된 성능 저하 구현을 확인하십시오.

에서 반환 한 값 element.getBoundingClientRect()은 뷰포트와 관련이 있습니다. 다른 요소와 관련하여 필요하면 하나의 사각형을 다른 사각형에서 빼십시오.

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');

143
JS 좌표에 관한 매우 흥미로운 기사 . 이 기사는 어디에도 언급되어 있지 않다 ..
e2-e4

6
작동하지 않습니다 ... 본체의 8px 여백으로 인해 세로 및 가로로 8 픽셀이 나옵니다. Meouw의 솔루션은 완벽하게 작동합니다. 원하는 경우 문제를 시연하기위한 작은 테스트가 있습니다.
CpnCrunch 2

3
실제로, 나는 그것이 실제로 당신이 원하는 것을 얻는 것에 달려 있다고 생각합니다. 문제는 조금 모호합니다. 뷰포트 또는 바디 요소와 관련된 좌표를 원한다면 대답은 정확하지만 요소의 절대 위치를 원할 경우 도움이되지 않습니다 (대부분의 사람들이 원하는 것입니다) . meouw의 대답은 '-scrollLeft'및 '-scrollTop'비트를 제거하지 않는 한 그중 하나도 제공하지 않습니다.
CpnCrunch

4
@CpnCrunch : 나는 당신이 지금 무엇을 의미하는지 봅니다; 나는 당신이 내 대답의 후반 부분을 언급하고 있다는 것을 몰랐습니다. 본문에 여백이 있으면 해당 경계 상자가 각 측면의 해당 픽셀 수만큼 오프셋됩니다. 이 경우 바디 좌표에서 계산 된 여백 스타일을 빼야합니다. CSS 재설정으로 마진을 제거한다는 점은 주목할 가치가 <body>있습니다.
Andy E

3
element.getBoundingClientRect().topposition: fixediOS (iPhone 8)의 요소가 포커스 된 입력 요소를 포함하고 가상 키보드가 미끄러 져 들어간 경우 올바른 상단 오프셋을 반환하지 않습니다 . 예를 들어, 창의 상단에서 실제 오프셋이 200px 인 경우 420px로보고합니다. 여기서 220px는 가상 키보드의 높이입니다. 요소를 설정 position: absolute하고 고정 된 것과 동일한 위치에 배치하면 올바른 200px를 얻을 수 있습니다. 나는 이것에 대한 해결책을 모른다.
Jānis Elmeris

327

라이브러리는 요소의 정확한 오프셋을 얻기 위해 일정 길이로 이동합니다.
여기 내가 시도한 모든 상황에서 작업을 수행하는 간단한 기능이 있습니다.

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 

14
el = el.parentNode를 다음과 같이 변경합니다. el = el.offsetParent; 중첩 된 iframe에서 작동하는 것 같습니다 ... 나는 그것이 당신이 의도 한 것이라고 생각합니까?
Adam

4
이 솔루션은 불완전합니다. div에 두꺼운 테두리를 놓고 몇 번 중첩시킵니다. Firefox (2-5)의 모든 버전에서 (표준 준수 모드에서도) 경계 너비만큼 꺼집니다.
ck_

3
el.totalOffsetLeft 및 totalOffsetTop 함수와 같이 더 깔끔한 방법이 있습니까? jQuery에는 확실히이 옵션이 있지만 공식적인 방법이 없다는 것이 부끄러운 일입니다. DOM4를 기다려야합니까? HTML5 캔버스 응용 프로그램을 작성 중이므로 가장 좋은 솔루션은 iframe에 캔버스 요소를 삽입하여 요소를 클릭하면 clientX 및 clientY와 실제 좌표를 얻을 수 있다고 생각합니다.
baptx

1
@Adam과 meouw, 첫 번째 코드 블록이 잘못되었다고 말하는가? 그렇다면 왜 완전히 제거하지 않습니까? (이 질문은 몇 년 동안 꽤 많은 시청자를 보았습니다. 틀린 경우 제거하는 것이 좋을까요?)
Arjan

2
@ baptx : 나는 이것이 늦게 답한다는 것을 알고 있지만, 나는 당신의 의견을 빨리 보지 못했습니다. 더 많은 표준 호환 대안에 대해서는 아래 답변을 참조하십시오. 브라우저는 오랫동안 코드를 지원했기 때문에 실제로 대체 코드가 필요하지 않습니다.
Andy E

242

이것은 나를 위해 일했습니다 (최고 투표 답변에서 수정 됨).

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

이것을 사용하여 우리는 전화 할 수 있습니다

getOffset(element).left

또는

getOffset(element).top

1
divCSS를 사용하여 요소 를 중심에 배치 할 때이 솔루션 만 효과가 있습니다 top:50%, left:50%; transform:translate(-50%, -50%);... @ScottBiggs 질문 오순절에 동의합니다. 논리적은 단순성을 추구하는 것입니다.
nelek

3
아마 앤디 E의 솔루션으로 그 같은 원인이 아니 승자하지만 오래된 브라우저 <IE9에없는 작업을 수행
niltoid

getBoundingClientRect가 내 성능 차트에서 막대한 재 페인트 급증을
일으킴

1
당신은 정의해야 rect사용 var, let또는 const. 그렇지 않으면로 정의됩니다 window.rect.
hev1

2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)요소의 중간 위치를 반환합니다
abhishake

96

javascript 만 사용하려면 다음을 사용 하는 한 가지 라이너가 있습니다.getBoundingClientRect()

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

첫 번째 줄은 offsetTop문서에 대해 Y라고 말합니다. 두 번째 줄은 offsetLeft문서에 대해 X라고 말합니다.

getBoundingClientRect() 창의 뷰포트를 기준으로 요소의 위치를 ​​반환하는 자바 스크립트 함수입니다.


2
이것이 해결책이되어야합니다. 여기에 긴 코드 bs가 없으며 이해할 수 있고 매우 정확합니다!
E Alexis MT

2
요소가 스크롤 가능한 요소 내에 있으면 어떻게합니까? 다른 답변이 제안처럼 그것을 할 수있는 유일한 방법은 모든 부모 요소의 offsetTop을 요약하는 것입니다
드미트리 Pisarev

드미트리 (Dmitri)가 말했듯이, 이것은 부정확하고 결함이 있습니다. 투표 수만큼 많지 않아야합니다. 문서 자체를 스크롤 할 수 있기 때문에 항상 스크롤 가능한 요소에 있습니다. 즉, 전체 문서가 뷰포트에 맞지 않으면 사용자가 기본 창을 스크롤 한 경우 항상 올바르지 않습니다.
레프

46

대부분의 브라우저에서 HTML 요소는 다음과 같습니다.

offsetLeft
offsetTop

이들은 레이아웃을 가진 가장 가까운 부모를 기준으로 요소의 위치를 ​​지정합니다. 이 부모는 종종 offsetParent 속성을 통해 액세스 할 수 있습니다.

IE와 FF3은

clientLeft
clientTop

이러한 속성은 덜 일반적이며 부모 클라이언트 영역과 함께 요소 위치를 지정합니다 (패딩 영역은 클라이언트 영역의 일부이지만 테두리와 여백은 아닙니다).


36

페이지에 최소한 "DIV"가 포함되어 있으면 meouw에서 제공하는 함수는 "Y"값을 현재 페이지 제한을 초과하여 발생시킵니다. 정확한 위치를 찾으려면 offsetParent와 parentNode를 모두 처리해야합니다.

아래에 주어진 코드를 사용해보십시오 (FF2가 확인 됨).


var getAbsPosition = function(el){
    var el2 = el;
    var curtop = 0;
    var curleft = 0;
    if (document.getElementById || document.all) {
        do  {
            curleft += el.offsetLeft-el.scrollLeft;
            curtop += el.offsetTop-el.scrollTop;
            el = el.offsetParent;
            el2 = el2.parentNode;
            while (el2 != el) {
                curleft -= el2.scrollLeft;
                curtop -= el2.scrollTop;
                el2 = el2.parentNode;
            }
        } while (el.offsetParent);

    } else if (document.layers) {
        curtop += el.y;
        curleft += el.x;
    }
    return [curtop, curleft];
};


1
FF 24.4에서도 다른 솔루션과 마찬가지로 위의 코드는 테두리 너비가 위치 지정 레이아웃의 일부로 존재할 때 작동하지 않습니다.
rob

당신은 생명의 은인입니다. 나는 지금 꽤 깊은 GWT 버그를 연구하고 있으며 JSNI 방법으로 던지면 내 모든 문제가 해결됩니다!
Will Byrne 2016 년

35

Element.prototype요소의 상단 / 왼쪽을 얻기 위해 두 가지 속성을 추가 할 수 있습니다 .

Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
    get: function () { 
        return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
    }
} );

이것을 다음과 같이 부릅니다.

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

다음은 jQuery offset().top와 결과를 비교하는 데모입니다 .left. http://jsfiddle.net/ThinkingStiff/3G7EZ/


14
수정 Element.prototype은 일반적으로 나쁜 생각 으로 간주됩니다 . 코드를 유지하기가 정말 어렵습니다. 또한이 코드는 스크롤을 설명하지 않습니다.
Jared Forsyth

23

재귀 함수를 사용하지 않고 페이지와 관련된 위치를 효율적으로 검색하려면 : (IE도 포함)

var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
                document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?                   
                 document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;

중요한 모든 scrollTop / scrollLeft를 포함하면이 대답이 약간 더 정확 해집니다.
scunliffe

19

요소의 ID를 전달하여 왼쪽 또는 위쪽을 반환하면 다음과 같이 결합 할 수 있습니다.

1) 왼쪽 찾기

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2) 상단 찾기

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

또는 3) 왼쪽과 상단을 함께 찾으십시오.

function findTopLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');

16

브라우저 독립적 인 방식으로 그러한 정보 (및 훨씬 더!)를 리턴하는 기능이있는 JavaScript 프레임 워크를 사용하면 더 나은 결과를 얻을 수 있습니다. 몇 가지가 있습니다 :

이러한 프레임 워크를 사용 $('id-of-img').top 하면 이미지의 y 픽셀 좌표를 얻기 위해 다음과 같은 작업을 수행 할 수 있습니다.


2
@Costa 서로 다른 브라우저는 사양에 따라 다르게 적용되므로 진화하는 분야이지만 모두 이러한 종류의 기능을 사용합니다. 많은 코드가 잘못되는 "고정"문제를 처리합니다. 당신은 정말로 소스 코드를 봐야합니다.
Shalom Craimer

18
@ scraimer : jQuery와 YUI는 프레임 워크아닙니다 !!! 이것들은 도서관입니다 ! 이건 같은게 아니야. jquery.com 인용 : "jQuery는 빠르고 작고 기능이 풍부한 JavaScript 라이브러리 입니다." yuilibrary.com 인용 (URL에서도 "매직"단어를 볼 수 있습니다 ...) : "YUI는 풍부한 대화식 웹 응용 프로그램을 구축하기위한 무료 오픈 소스 JavaScript 및 CSS 라이브러리 입니다."
Sk8erPeter 11

29
따라서이 간단한 작업에만 거대한 라이브러리를 사용해야합니까? 필요하지 않습니다. 나는 js로 무언가를하고 싶을 때 마다이 jQuery 솔루션을 얻는 것이 싫어. jQuery는 JS가 아닙니다!
Opptatt Jobber

1
@OpptattJobber 동의합니다 ... JQuery는 자바 스크립트가 아닙니다. Javascript를 사용하지만 다른 프로그래밍 언어를 사용합니다.
Nick Manning

5
@NickManning 새로운 언어가 아니며 DOM에 대한 추상화 계층으로 호환성 및 성능 해결 방법을 코드에 직접 작성할 필요가 없습니다. jQuery를 사용하지 않으면 어쨌든 일부 유형의 추상화 계층을 사용해야합니다.
ginman

15

jQuery .offset () 은 첫 번째 요소의 현재 좌표를 가져 오거나 일치하는 요소 세트에서 문서를 기준으로 모든 요소의 좌표를 설정합니다.


어떤 이유로 IE에서 다른 브라우저와 동일한 결과를 제공하지 않습니다. 나는 IE에서 그것은 창에 상대적으로 위치를 제공한다고 생각합니다. 그래서 스크롤하면, 당신은 다른 것과 비교하여 IE에서 다른 결과를 얻을 것입니다
Abdul Rahim Haddad

1
offset ()은 적어도 Android Chrome에서 줌과 혼동되므로 쓸모가 없습니다. stackoverflow.com/a/11396681/1691517 은 줌 허용 방식을 보여줍니다.
Timo Kähkönen

10

@meouw의 답변을 가져 와서 테두리를 허용하는 clientLeft에 추가 한 다음 세 가지 버전을 만들었습니다.

getAbsoluteOffsetFromBody-@meouw와 유사하며 문서의 본문 또는 HTML 요소에 상대적인 절대 위치를 가져옵니다 (쿼크 모드에 따라 다름)

getAbsoluteOffsetFromGivenElement-주어진 요소 (상대 El)에 상대적인 절대 위치를 반환합니다. 주어진 요소는 요소 el을 포함해야합니다. 그렇지 않으면 getAbsoluteOffsetFromBody와 동일하게 작동합니다. 다른 (알려진) 요소 (선택적으로 노드 트리 위의 여러 노드) 내에 두 개의 요소가 포함되어 있고 동일한 위치로 만들려는 경우에 유용합니다.

getAbsoluteOffsetFromRelative-position : relative를 사용하여 첫 번째 상위 요소에 상대적인 절대 위치를 리턴합니다. 이것은 같은 이유로 getAbsoluteOffsetFromGivenElement와 유사하지만 첫 번째 일치하는 요소까지만 진행됩니다.

getAbsoluteOffsetFromBody = function( el )
{   // finds the offset of el from the body or html element
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{   // finds the offset of el from relativeEl
    var _x = 0;
    var _y = 0;
    while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromRelative = function( el )
{   // finds the offset of el from the first parent with position: relative
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
        if (el != null)
        {
            if (getComputedStyle !== 'undefined')
                valString = getComputedStyle(el, null).getPropertyValue('position');
            else
                valString = el.currentStyle['position'];
            if (valString === "relative")
                el = null;
        }
    }
    return { top: _y, left: _x };
}

여전히 스크롤과 관련하여 여전히 문제가있는 경우 http://www.greywyvern.com/?post=331을 살펴보십시오. 브라우저가 작동한다고 가정하면 getStyle에서 적어도 하나의 의심스러운 코드가 발견되었습니다. , 나머지는 전혀 테스트하지 않았습니다.


재미있는 ...하지만 Edge에서 getAbsoluteOffsetFromBody (element) .top은 스크롤 할 때 다른 값을 반환하며 Chrome에서는 스크롤 할 때 일관성을 유지합니다. Edge가 스크롤 위치로 조정되는 것 같습니다. 요소가 화면 밖으로 스크롤되면 음수 값을 얻습니다.
Norman

getAbsoluteOffsetFromRelative는 하루를 보냈습니다. 부트 스트랩의 Javascript없이 부트 스트랩 툴팁을 재현해야했습니다. 많은 도움이되었습니다.
Nolyurn

Meouw가 사용자 이름을 변경하는 경우, stackoverflow.com/a/442474/3654837로 링크하십시오 . (나는이 오래된 실을 부딪치지 않기를 원한다. 그래서 나는 의견을
달았다

8

jQuery를 사용하는 경우 치수 플러그인 이 우수하며 원하는 것을 정확하게 지정할 수 있습니다.

예 :

패딩이있는 상대 위치, 절대 위치, 패딩이없는 절대 위치 ...

계속해서 할 수있는 일이 많다고하자.

또한 jQuery를 사용하면 파일 크기가 가볍고 사용하기 쉬워 나중에 자바 스크립트로 돌아 가지 않아도됩니다.


8

이것은 jQuery의 offset ()과 달리 iframe에서 작동하는 최고의 코드입니다. 웹킷에는 약간 다른 동작이있는 것 같습니다.

meouw의 의견을 바탕으로 :

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        // chrome/safari
        if ($.browser.webkit) {
            el = el.parentNode;
        } else {
            // firefox/IE
            el = el.offsetParent;
        }
    }
    return { top: _y, left: _x };
}

당신이해야합니다 jQuery사용하는 $.browser.webkit; navigator.userAgentpure와 동일하게 작동하려면 놀아야 JavaScript합니다.
SP

2
$ .browser는 더 이상 최신 버전의 jQuery에서 사용할 수 없습니다
Gus

불행히도 FF 24.4에서도 테두리 너비가 위치 지정 레이아웃의 일부로 존재하면 위의 코드가 작동하지 않습니다.
rob

8

jQuery를 사용하는 경우 간단한 해결책이 될 수 있습니다.

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>

8

작고 작은 차이

function getPosition( el ) {
    var x = 0;
    var y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
    x += el.offsetLeft - el.scrollLeft;
    y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
    }
    return { top: y, left: x };
}

좌표 예를보십시오 : http://javascript.info/tutorial/coordinates


불행히도 현대 HTML 문서에서 찾을 수있는 모든 요소에 대해 작동하지는 않습니다. 임베디드 <svg>요소, 예를 들어,이없는 offsetLeft, offsetTop그리고 offsetParent속성.
Jonathan Eunice

그냥 DIV또는 IMG아닙니다 SVG. "예제보기"를 보시겠습니까? 당신은 객체 svg 찾을 위치 호출 getOffsetRect 찾을 수 객체 작업을 시도하고 의존합니다.
KingRider

7

내가 찾은 가장 깨끗한 접근 방식은 jQuery가 사용하는 기술의 단순화 된 버전입니다 offset. 다른 답변 중 일부와 비슷합니다 getBoundingClientRect. 그런 다음 사용 window과를 documentElement온 여백 같은 스크롤 위치뿐만 아니라 것들에 대한 조정 body(보통 기본값).

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;


6

이것이 많은 답변의 맨 아래에서 잃어 버릴 가능성이 높지만 여기에있는 최고의 솔루션은 효과가 없었습니다.
내가 알 수있는 한 다른 답변은 도움이되지 않았습니다.

상황 :
HTML5 페이지에는 헤더 내부의 탐색 요소 인 메뉴 (헤더가 아닌 다른 요소의 헤더)가 있습니다.
사용자가 스크롤하면 탐색 기능이 맨 위에 고정되기를 원했지만 이전에는 헤더가 절대 위치되었습니다 (따라서 약간 다른 것을 오버레이 할 수 있음).
위의 솔루션은 절대 위치 요소이므로 .offsetTop이 변경되지 않았기 때문에 변경 사항을 트리거하지 않았습니다. 또한 .scrollTop 속성은 단순히 최상위 요소 중 최상위 요소였습니다. 즉 0은 항상 0입니다.
이 두 가지 (getBoundingClientRect 결과와 동일)를 사용하여 수행 한 모든 테스트는 탐색 표시 줄의 상단이 볼 수있는 페이지의 상단으로 스크롤되었는지 여부를 알려주지 않습니다 (콘솔에서보고 된 것처럼 스크롤하면서 동일한 숫자를 유지했습니다) 발생).

솔루션
나를위한 솔루션을 활용하고있었습니다

window.visualViewport.pageTop

pageTop 속성의 값은 화면의 볼 수있는 섹션을 반영하므로 볼 수있는 영역의 경계를 기준으로 요소가있는 위치를 추적 할 수 있습니다.

스크롤을 처리 할 때 마다이 솔루션을 사용하여 스크롤되는 요소의 움직임에 프로그래밍 방식으로 응답 할 것으로 예상됩니다.
그것이 다른 누군가를 돕기를 바랍니다.
중요 참고 사항 : Firefox 및 VisualViewport를 지원하기 전까지 는 Chrome 및 Opera에서 현재 및 Firefox (6-2018) 에서는 작동하지 않는 것으로 보입니다. 나머지보다 더 의미가 있습니다).


업데이트 :
이 솔루션에 관한 참고 사항.
나는 여전히 "... 스크롤되는 요소의 움직임에 프로그래밍 방식으로 반응하는"상황에서 매우 귀중한 것으로 발견했습니다. 적용 가능합니다. 내가 가진 문제에 대한 더 좋은 해결책은 CSS를 사용하여 위치 를 설정하는 것이 었 습니다.요소에. sticky를 사용하면 javascript를 사용하지 않고 맨 위에 요소를 유지할 수 있습니다 (참고 : 요소를 고정으로 변경하는 것만 큼 효과적이지 않지만 대부분의 경우 sticky 방식이 우수 할 수 있습니다)

UPDATE01 :
그래서 나는 깨달았습니다. 다른 페이지의 경우 약간 복잡한 스크롤 설정 (패럴 렉스 + 메시지의 일부로 스크롤되는 요소)에서 요소의 위치를 ​​감지 해야하는 요구 사항이있었습니다. 나는 그 시나리오에서 다음이 내가 무엇을해야 할지를 결정하는 데 활용 한 가치를 제공한다는 것을 깨달았습니다.

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

이 답변이 더 널리 유용하기를 바랍니다.


클릭 하면 답변을 정렬하기 위해 활성 을 클릭 할 때 매우 많은 답변의 맨 위에있을 가능성이 높습니다.
lucchi

@lucchi : D 잘 나는 텍스트를 상단에서 제거 할 수 있다고 생각합니다 ... 방금 다시이 문제가 발생했지만 내 문제에 대한 더 나은 해결책을 찾았다는 것을 깨달았습니다 ... 내 대답은 더 많지만 더 완전한 답변에 발 메모. 내 요구 사항이 다른 답변이 저에게 효과가 없다는 것이 일반적이지 않은 것 같습니다.
MER

1
어쨌든 당신의 대답에 감사드립니다. 그것은 단지 당신이 무언가 새로운 것을 썼다는 것을 기꺼이 알고 있다는 것입니다. 당신은 혼자가 아닙니다 ....
lucchi

5

나는 이것을 오래된 브라우저와 호환되도록 그렇게했습니다.

// For really old browser's or incompatible ones
    function getOffsetSum(elem) {
        var top = 0,
            left = 0,
            bottom = 0,
            right = 0

         var width = elem.offsetWidth;
         var height = elem.offsetHeight;

        while (elem) {
            top += elem.offsetTop;
            left += elem.offsetLeft;
            elem = elem.offsetParent;
        }

         right = left + width;
         bottom = top + height;

        return {
            top: top,
            left: left,
            bottom: bottom,
            right: right,
        }
    }

    function getOffsetRect(elem) {
        var box = elem.getBoundingClientRect();

        var body = document.body;
        var docElem = document.documentElement;

        var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
        var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;

        var clientTop = docElem.clientTop;
        var clientLeft = docElem.clientLeft;


        var top = box.top + scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
        var bottom = top + (box.bottom - box.top);
        var right = left + (box.right - box.left);

        return {
            top: Math.round(top),
            left: Math.round(left),
            bottom: Math.round(bottom),
            right: Math.round(right),
        }
    }

    function getOffset(elem) {
        if (elem) {
            if (elem.getBoundingClientRect) {
                return getOffsetRect(elem);
            } else { // old browser
                return getOffsetSum(elem);
            }
        } else
            return null;
    }

JavaScript 좌표에 대한 자세한 내용은 다음을 참조하십시오. http://javascript.info/tutorial/coordinates


4

요소의 총 오프셋을 얻으려면 모든 부모 오프셋을 재귀 적으로 요약 할 수 있습니다.

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

이 유틸리티 기능을 사용하면 dom 요소의 총 상단 오프셋은 다음과 같습니다.

el.offsetTop + getParentOffsets(el);

3
/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    var position = {
        top: el.offsetTop,
        left: el.offsetLeft
    };
    if (el.offsetParent) {
        var parentPosition = getDocumentOffsetPosition(el.offsetParent);
        position.top += parentPosition.top;
        position.left += parentPosition.left;
    }
    return position;
}

정답에 대해 ThinkingStiff 에게 감사드립니다 . 이것은 다른 버전 일뿐입니다.


2

Andy E의 솔루션을 사용하여 사용자가 클릭하는 테이블 행의 링크에 따라 부트 스트랩 2 모달을 배치했습니다. 페이지는 Tapestry 5 페이지이며 아래의 자바 스크립트는 java 페이지 클래스에서 가져옵니다.

자바 스크립트 :

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

내 모달 코드 :

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" 
 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
    <h3 id="myModalLabel">Modal header</h3>
</div>

<div class="modal-body">
    <t:zone t:id="modalZone" id="modalZone">
        <p>You selected service line number: ${serviceLineNumberSelected}</p>
    </t:zone>
</div>

<div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <!-- <button class="btn btn-primary">Save changes</button> -->
</div>

루프의 링크 :

<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">       
    <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> 
        <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" 
            t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
            onmouseover="setLinkPosition(this);">
            <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
        </a>
    </td>

그리고 페이지 클래스의 자바 코드 :

void onServiceLineNumberSelected(String number){
    checkForNullSession();
    serviceLineNumberSelected = number;
    addOpenServiceLineDialogCommand();
    ajaxResponseRenderer.addRender(modalZone);
}

protected void addOpenServiceLineDialogCommand() {
    ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
        @Override
        public void run(JavaScriptSupport javascriptSupport) {
            javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
        }
    });
}

이것이 누군가에게 도움이되기를 바랍니다.이 게시물이 도움이되었습니다.


이 js 코드는 여러 자리 표시자를 사용하여 .aspx 페이지를 삽입하는 오래된 webforms 앱을 가지고 있으며 전체 DOM 트리가 손상되어 뷰포트에 가져 오기 위해 만든 팝업 상자의 child ()를 추가하는 방법을 알 수 없었습니다. 여러 자리 표시 자와 잘못된 마크 업 body.getBoundingClientRect ()를 사용하고 포지셔닝에서 상단을 사용하는 것이 필요했습니다. 감사.
Brad Martin

1

많은 연구와 테스트를 거친 후 작동하는 것 같습니다.

function getPosition(e) {
    var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
    var x = 0, y = 0;
    while (e) {
        x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
        y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
        e = e.offsetParent;
    }
    return { x: x + window.scrollX, y: y + window.scrollY };
}

http://jsbin.com/xuvovalifo/edit?html,js,output 참조


1

방금 이것도 내가 버릴 것이라고 생각했습니다.
구형 브라우저에서는 테스트 할 수 없지만 최신 3 위에서 작동합니다. :)

Element.prototype.getOffsetTop = function() {
    return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
    return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
    return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};

0

브라우저마다 다른 방식으로 테두리, 패딩, 여백 등을 렌더링합니다. 정확한 치수로 원하는 모든 루트 요소에서 특정 요소의 상단 및 왼쪽 위치를 검색하는 작은 함수를 작성했습니다.

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

왼쪽 위치를 검색하려면 다음을 반환해야합니다.

    return offsetRect.left - rootRect.left;

-1

왼쪽 및 상단에 대한 div 위치 가져 오기

  var elm = $('#div_id');  //get the div
  var posY_top = elm.offset().top;  //get the position from top
  var posX_left = elm.offset().left; //get the position from left 

아래쪽과 오른쪽이 offset ()의 속성이 아니기 때문에
투표권을 얻었습니다.

@MacroMan, 나는 당신의 결정을 존중하지만 텍스트에서 "아래와 오른쪽 코드는 테스트되지 않았다"고 이미 설명했습니다. 또한 코드를 곧 업데이트 할 예정입니다.
Vishal

나는 그것이 생각 el.offsetTop하고 el.offsetLeft(OP는 jQuery에 대해 아무 말도하지 않습니다 ... 왜 당신의 대답이 jQuery를 사용하는지 모르겠습니다 ...)
mesqueeb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.