我想知道如何相对于浏览器窗口获取HTML元素(例如img
和div
在JavaScript中)的X和Y位置。
我想知道如何相对于浏览器窗口获取HTML元素(例如img
和div
在JavaScript中)的X和Y位置。
Answers:
正确的方法是使用element.getBoundingClientRect()
:
var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
Internet Explorer自从您很可能就一直在支持此功能,并且最终在CSSOM Views中对其进行了标准化。其他所有浏览器在很久以前就采用了它。
一些浏览器还返回height和width属性,尽管这是非标准的。如果您担心与旧版浏览器的兼容性,请查看此答案的修订版以实现优化的降级实现。
返回的值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()
是一个javascript函数,它返回元素相对于窗口视口的位置。
如果页面至少包含“ 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-返回相对于给定元素(relativeEl)的绝对位置。请注意,给定元素必须包含元素el,否则其行为与getAbsoluteOffsetFromBody相同。如果您在另一个(已知)元素中包含两个元素(可选地,节点树中有多个节点),并且希望使它们处于相同位置,则这很有用。
getAbsoluteOffsetFromRelative-返回相对于具有位置: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,则Dimensions插件非常出色,可让您准确指定所需的内容。
例如
相对位置,绝对位置,不带填充的绝对位置,带填充...
它还在继续,让我们说您可以做很多事情。
加上使用jQuery的好处是它的文件大小轻巧且易于使用,如果没有它,您将不会再使用JavaScript。
这是我设法创建的最佳代码(与jQuery的offset()不同,它也可以在iframe中使用)。似乎webkit有一些不同的行为。
根据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,这可能是一个简单的解决方案:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
小与小的区别
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页面中,我有一个菜单,该菜单是标题中的nav元素(不是THE标题,而是另一个元素中的标题)。
我希望导航在用户滚动到顶部时停留在顶部,但是在此之前,页眉是绝对定位的(因此我可以将其稍微覆盖一下)。
上面的解决方案从未触发更改,因为.offsetTop不会更改,因为这是绝对定位的元素。此外,.scrollTop属性只是最上面的元素的顶部...也就是说0,并且始终为0。
我使用这两项进行的任何测试(与getBoundingClientRect结果相同)都不会告诉我导航栏的顶部是否曾经滚动到可见页面的顶部(再次,如控制台中所报告的那样,它们在滚动时仅保持相同的数字)发生了)。
解决
方案对我来说,解决方案是利用
window.visualViewport.pageTop
pageTop属性的值反映了屏幕的可视区域,因此允许我跟踪元素在可视区域边界上的引用。
也许无需多说,每当我要处理滚动时,我都希望使用此解决方案以编程方式响应被滚动元素的运动。
希望它可以帮助别人。
重要说明:这似乎目前在Chrome和Opera中有效,并且在Firefox(6-2018)中绝对不可用 ...直到Firefox支持visualViewport之前,我建议不要使用此方法,(并且我希望它们能尽快使用...这很有帮助。比其余的更有意义)。
更新:
只是有关此解决方案的说明。
虽然我仍然发现我发现的内容对于“ ...以编程方式响应所滚动元素的移动”的情况非常有价值。适用。对于我遇到的问题,更好的解决方案是使用CSS设置位置:粘性在元素上。使用sticky,您可以不使用javascript就将元素保留在顶部(注意:有时候,这不能像将元素更改为fixed那样有效,但是对于大多数使用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的解决方案来根据用户单击表行中的链接来定位bootstrap 2模态。该页面是Tapestry 5页面,下面的javascript被导入到Java页面类中。
javascript:
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>
以及页面类中的Java代码:
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()};
};
获取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
(任择议定书并没有说明什么jQuery的...我不知道为什么你的答案用了jQuery要么...)