브라우저 창을 기준으로 JavaScript img
와 같은 HTML 요소의 X 및 Y 위치를 얻는 방법을 알고 싶습니다 div
.
브라우저 창을 기준으로 JavaScript img
와 같은 HTML 요소의 X 및 Y 위치를 얻는 방법을 알고 싶습니다 div
.
답변:
올바른 접근 방식은 다음을 사용하는 것입니다 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>');
<body>
있습니다.
element.getBoundingClientRect().top
position: fixed
iOS (iPhone 8)의 요소가 포커스 된 입력 요소를 포함하고 가상 키보드가 미끄러 져 들어간 경우 올바른 상단 오프셋을 반환하지 않습니다 . 예를 들어, 창의 상단에서 실제 오프셋이 200px 인 경우 420px로보고합니다. 여기서 220px는 가상 키보드의 높이입니다. 요소를 설정 position: absolute
하고 고정 된 것과 동일한 위치에 배치하면 올바른 200px를 얻을 수 있습니다. 나는 이것에 대한 해결책을 모른다.
라이브러리는 요소의 정확한 오프셋을 얻기 위해 일정 길이로 이동합니다.
여기 내가 시도한 모든 상황에서 작업을 수행하는 간단한 기능이 있습니다.
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;
이것은 나를 위해 일했습니다 (최고 투표 답변에서 수정 됨).
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
이것을 사용하여 우리는 전화 할 수 있습니다
getOffset(element).left
또는
getOffset(element).top
div
CSS를 사용하여 요소 를 중심에 배치 할 때이 솔루션 만 효과가 있습니다 top:50%, left:50%; transform:translate(-50%, -50%);
... @ScottBiggs 질문 오순절에 동의합니다. 논리적은 단순성을 추구하는 것입니다.
rect
사용 var
, let
또는 const
. 그렇지 않으면로 정의됩니다 window.rect
.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
요소의 중간 위치를 반환합니다
javascript 만 사용하려면 다음을 사용 하는 한 가지 라이너가 있습니다.getBoundingClientRect()
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
첫 번째 줄은 offsetTop
문서에 대해 Y라고 말합니다. 두 번째 줄은 offsetLeft
문서에 대해 X라고 말합니다.
getBoundingClientRect()
창의 뷰포트를 기준으로 요소의 위치를 반환하는 자바 스크립트 함수입니다.
대부분의 브라우저에서 HTML 요소는 다음과 같습니다.
offsetLeft
offsetTop
이들은 레이아웃을 가진 가장 가까운 부모를 기준으로 요소의 위치를 지정합니다. 이 부모는 종종 offsetParent 속성을 통해 액세스 할 수 있습니다.
IE와 FF3은
clientLeft
clientTop
이러한 속성은 덜 일반적이며 부모 클라이언트 영역과 함께 요소 위치를 지정합니다 (패딩 영역은 클라이언트 영역의 일부이지만 테두리와 여백은 아닙니다).
페이지에 최소한 "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];
};
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/
Element.prototype
은 일반적으로 나쁜 생각 으로 간주됩니다 . 코드를 유지하기가 정말 어렵습니다. 또한이 코드는 스크롤을 설명하지 않습니다.
재귀 함수를 사용하지 않고 페이지와 관련된 위치를 효율적으로 검색하려면 : (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;
요소의 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');
브라우저 독립적 인 방식으로 그러한 정보 (및 훨씬 더!)를 리턴하는 기능이있는 JavaScript 프레임 워크를 사용하면 더 나은 결과를 얻을 수 있습니다. 몇 가지가 있습니다 :
이러한 프레임 워크를 사용 $('id-of-img').top
하면 이미지의 y 픽셀 좌표를 얻기 위해 다음과 같은 작업을 수행 할 수
있습니다.
jQuery .offset () 은 첫 번째 요소의 현재 좌표를 가져 오거나 일치하는 요소 세트에서 문서를 기준으로 모든 요소의 좌표를 설정합니다.
@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에서 적어도 하나의 의심스러운 코드가 발견되었습니다. , 나머지는 전혀 테스트하지 않았습니다.
이것은 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 };
}
작고 작은 차이
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
<svg>
요소, 예를 들어,이없는 offsetLeft
, offsetTop
그리고 offsetParent
속성.
DIV
또는 IMG
아닙니다 SVG
. "예제보기"를 보시겠습니까? 당신은 객체 svg 찾을 위치 호출 getOffsetRect 찾을 수 객체 작업을 시도하고 의존합니다.
내가 찾은 가장 깨끗한 접근 방식은 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;
이것이 많은 답변의 맨 아래에서 잃어 버릴 가능성이 높지만 여기에있는 최고의 솔루션은 효과가 없었습니다.
내가 알 수있는 한 다른 답변은 도움이되지 않았습니다.
상황 :
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 = '';
}
이 답변이 더 널리 유용하기를 바랍니다.
나는 이것을 오래된 브라우저와 호환되도록 그렇게했습니다.
// 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
/**
*
* @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 에게 감사드립니다 . 이것은 다른 버전 일뿐입니다.
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');");
}
});
}
이것이 누군가에게 도움이되기를 바랍니다.이 게시물이 도움이되었습니다.
많은 연구와 테스트를 거친 후 작동하는 것 같습니다.
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 };
}
방금 이것도 내가 버릴 것이라고 생각했습니다.
구형 브라우저에서는 테스트 할 수 없지만 최신 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()};
};
브라우저마다 다른 방식으로 테두리, 패딩, 여백 등을 렌더링합니다. 정확한 치수로 원하는 모든 루트 요소에서 특정 요소의 상단 및 왼쪽 위치를 검색하는 작은 함수를 작성했습니다.
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
왼쪽 위치를 검색하려면 다음을 반환해야합니다.
return offsetRect.left - rootRect.left;
왼쪽 및 상단에 대한 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
el.offsetTop
하고 el.offsetLeft
(OP는 jQuery에 대해 아무 말도하지 않습니다 ... 왜 당신의 대답이 jQuery를 사용하는지 모르겠습니다 ...)