브라우저의 뷰포트를 기준으로 요소의 최상위 위치를 얻는 방법은 무엇입니까?


173

브라우저의 뷰포트 (페이지 전체가 아닌 페이지가 표시되는 뷰포트)를 기준으로 요소의 위치를 ​​가져 오려고합니다. JavaScript로 어떻게 이것을 할 수 있습니까?

많은 감사


2
이 질문은 stackoverflow.com/questions/211703/… 과 비슷하다고 생각합니다 . 정말 좋은 해결책이 있습니다.
Jakob Runge

1
@JakobRunge, 2013 년에 "좋은"것이 었습니까?
Iulian Onofrei

1
솔루션 수락을 고려하십시오.
Iulian Onofrei

답변:


305

기존 답변은 이제 구식입니다. 기본 getBoundingClientRect()방법은 꽤 오랫동안 사용되어 왔으며 질문이 요구하는 것을 정확하게 수행합니다. 또한 모든 브라우저에서 지원됩니다 (IE 5 포함).

에서 MDN 페이지 :

반환 값은 TextRectangle 객체로, 뷰포트의 왼쪽 상단을 기준으로 왼쪽 상단을 기준으로 테두리 상자를 설명하는 읽기 전용 왼쪽, 위쪽, 오른쪽 및 아래쪽 속성을 픽셀 단위로 포함합니다 .

당신은 그렇게 사용합니다 :

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;

3
브라우저 확대 / 축소 (Android Chrome)를 사용하면 제대로 작동하지 않을 수 있습니다. 이 경우 @rism의 솔루션 ( 아래 참조 )이 작동합니다.
Dmitry

4
대부분의 경우에 좋지만 요소가 내장 iframe 안에 있지 않다고 가정합니다. 질문은 브라우저의 창에 대한 상대적인 질문입니다. el.getBoundingClientRect ()는 브라우저 윈도우가 아닌 iframe 윈도우를 상대적으로 반환합니다.
cakidnyc

6
질문은 브라우저의 창에 대한 상대적인 질문입니다.
Dmitry Dvornikov

2
@Denilson getBoundingClientRect().top이 내 IE11에 없으면 0을 반환합니다. 해결책이 있습니다.
Arif

@Arif : 죄송하지만 문제를 재현 할 수 없습니다. 나는 이것을 IE11에서 테스트했지만 여전히 결과를 얻었습니다 : codepen.io/denilsonsa/pen/ypqyXj
Denilson Sá Maia

57

필자의 경우 스크롤과 관련하여 안전하기 위해 window.scroll을 방정식에 추가했습니다.

var element = document.getElementById('myElement');
var topPos = element.getBoundingClientRect().top + window.scrollY;
var leftPos = element.getBoundingClientRect().left + window.scrollX;

그러면 스크롤 된 경우에도 문서에서 요소의 실제 상대 위치를 얻을 수 있습니다.


2
스크롤 위치를 빼지 않고 추가해야합니까?
Iulian Onofrei

나는 대답을 찬성했지만 여전히 @lulian Onofrei가 맞습니다. 수정하십시오.
pmrotule

@Fabio getBoundingClientRect().top가 내 IE11에 없으면 0을 반환합니다. 해결책이 있습니다.
Arif

1
@Arif window.scrollY || window.pageYOffset는 지원을 향상시킬 수 있습니다
Fabian von Ellerts

@FabianvonEllerts :)
Arif

15

편집 : 페이지 스크롤을 설명하는 코드를 추가하십시오.

function findPos(id) {
    var node = document.getElementById(id);     
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
        } while (node = node.offsetParent);

        alert(curtop - curtopscroll);
    }
}

id 인수는 오프셋을 원하는 요소의 id입니다. quirksmode 포스트 에서 적응시키는 .


1
귀하의 답변에 감사하지만 내 질문을 오해했다고 생각합니다. 페이지와 관련하여 요소의 상단을 얻는 방법을 알고 있습니다. 내가하려고하는 것은 '뷰포트'(예 : 브라우저 창)와 관련된 위치를 얻는 것입니다. , 문서가 아님)
Waleed Eissa

죄송합니다. 'viewport'를 사용했습니다. 브라우저 크롬, 즉 북마크 도구 모음, 위치 표시 줄 등을 설명하고 싶다고 말하는 것입니까?
Derek Swingley

아니요, 페이지를 보는 창만 있습니다. 페이지가 스크롤되면 문서 상단과 다르고 그렇지 않으면 동일합니다.
Waleed Eissa

오 알겠습니다 어떻게 해야할지 모르겠습니다 ... 내가 뭔가를 생각해 내면 대답을 편집 할 것입니다.
Derek Swingley

좀 이보다 위의 코드를 만들어하지만 ... 작동 사용 offsetParent.scrollTop
데릭 Swingley을

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

이것은 뷰포트가 아니라 문서의 맨 위에서 계산 된 것 같습니다
Scott Leonard

6

당신은 시도 할 수 있습니다:

node.offsetTop - window.scrollY

뷰포트 메타 태그가 정의 된 Opera에서 작동합니다.


7
설명서를 올바르게 이해 하면offsetTop 가장 가까운 위치에 상대적입니다. 페이지 구조에 따라 루트 요소 일 수도 있고 아닐 수도 있습니다.
Denilson Sá Maia

5

jQuery는 이것을 매우 우아하게 구현합니다. jQuery의 소스를 보면 offset기본 구현 방법을 알 수 있습니다.

var rect = elem.getBoundingClientRect();
var win = elem.ownerDocument.defaultView;

return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
};

2

페이지 의 함수 는 브라우저보기 포트를 기준으로 전달 된 요소의 상단, 왼쪽, 높이 및 너비 좌표가있는 사각형을 반환합니다.

    localToGlobal: function( _el ) {
       var target = _el,
       target_width = target.offsetWidth,
       target_height = target.offsetHeight,
       target_left = target.offsetLeft,
       target_top = target.offsetTop,
       gleft = 0,
       gtop = 0,
       rect = {};

       var moonwalk = function( _parent ) {
        if (!!_parent) {
            gleft += _parent.offsetLeft;
            gtop += _parent.offsetTop;
            moonwalk( _parent.offsetParent );
        } else {
            return rect = {
            top: target.offsetTop + gtop,
            left: target.offsetLeft + gleft,
            bottom: (target.offsetTop + gtop) + target_height,
            right: (target.offsetLeft + gleft) + target_width
            };
        }
    };
        moonwalk( target.offsetParent );
        return rect;
}

2
function inViewport(element) {
    let bounds = element.getBoundingClientRect();
    let viewWidth = document.documentElement.clientWidth;
    let viewHeight = document.documentElement.clientHeight;

    if (bounds['left'] < 0) return false;
    if (bounds['top'] < 0) return false;
    if (bounds['right'] > viewWidth) return false;
    if (bounds['bottom'] > viewHeight) return false;

    return true;
}

출처


1

모든 답변에 감사드립니다. 프로토 타입에는 이미이를 수행하는 함수 (page () 함수)가있는 것 같습니다. 함수의 소스 코드를 보면 먼저 페이지 (예 : 문서 상단)를 기준으로 요소 오프셋 위치를 계산 한 다음 scrollTop을 뺍니다. 자세한 내용은 프로토 타입의 소스 코드를 참조하십시오.


좋은 결정. 브라우저에서 동일한 결과를 얻을 가능성이 높기 때문에 주요 라이브러리 중 하나를 사용하는 것이 가장 좋습니다. 궁금하다면 내 대답을 확인하십시오. 거기에있는 코드는이 작업을 수행하지만 브라우저에서 어떻게 유지되는지 모릅니다.
Derek Swingley

1

btn1웹 페이지에 id가있는 요소가 있고 jQuery가 포함되어 있다고 가정합니다 . 이것은 Chrome, FireFox, IE> = 9 및 Edge의 모든 최신 브라우저에서 작동했습니다. jQuery는 문서와 관련된 위치를 결정하는 데만 사용됩니다.

var screenRelativeTop =  $("#btn1").offset().top - (window.scrollY || 
                                            window.pageYOffset || document.body.scrollTop);

var screenRelativeLeft =  $("#btn1").offset().left - (window.scrollX ||
                                           window.pageXOffset || document.body.scrollLeft);

1
jQuery는 JavaScript입니다. 나는 당신이 "100 % 바닐라 / 순수한 JS가 아님"
hungerstar

그렇습니다.
Sunil

1

getBoundingClientRect()IE의 경우 개체 속성 값이 0으로 표시되는 경우 가 있습니다. 이 경우 display = 'block'요소 를 설정 해야합니다. 모든 브라우저에서 아래 코드를 사용하여 오프셋을 얻을 수 있습니다.

jQuery 기능 확장 :

(function($) {
    jQuery.fn.weOffset = function () {
        var de = document.documentElement;
        $(this).css("display", "block");
        var box = $(this).get(0).getBoundingClientRect();
        var top = box.top + window.pageYOffset - de.clientTop;
        var left = box.left + window.pageXOffset - de.clientLeft;
        return { top: top, left: left };
    };
}(jQuery));

사용하다 :

var elementOffset = $("#" + elementId).weOffset();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.