检索HTML元素的位置(X,Y)
我想知道如何在JavaScript中获取HTML元素(如img
和div
的X和Y位置。
正确的方法是使用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>');
库有一些长度来获得一个元素的准确偏移量。
这里有一个简单的function,可以在我尝试过的每种情况下完成这项工作。
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) { el = el.getBoundingClientRect(); return { left: el.left + window.scrollX, top: el.top + window.scrollY } }
使用这个我们可以打电话
getOffset(element).left
要么
getOffset(element).top
如果页面包含 – 至less – 任何“DIV”,则由meouw给出的函数会抛出“Y”值超出当前页面限制。 为了find确切的位置,你需要同时处理“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/
要有效地检索相对于页面的位置,而不使用recursion函数:(也包括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;
大多数浏览器上的HTML元素将具有: –
offsetLeft offsetTop
这些指定元素相对于其最近的具有布局的父级的位置。 这个父母通常可以通过offsetParent属性访问。
IE和FF3都有
clientLeft clientTop
这些属性不太常见,它们指定父级客户区域的元素位置(填充区域是客户区域的一部分,但边界和边界不是)。
通过使用JavaScript框架可以更好地服务,该框架具有以独立于浏览器的方式返回此类信息(以及更多!)的function。 这里有几个:
- 原型
- jQuery的
- MooTools的
- YUI(雅虎)
有了这些框架,你可以做一些事情: $('id-of-img').top
获取图像的y像素坐标。
jQuery .offset()将获得第一个元素的当前坐标,或者在匹配元素集合中相对于文档的每个元素的坐标。
怎么样这样的事情,通过传递元素的ID,它会返回左侧或顶部,我们可以结合他们:
1)find左边
function findLeft(element) { var rec = document.getElementById(element).getBoundingClientRect(); return rec.left + window.scrollX; } //call it like findLeft('#header');
2)find顶部
function findTop(element) { var rec = document.getElementById(element).getBoundingClientRect(); return rec.top + window.scrollY; } //call it like findTop('#header');
或者3)find左边和上面在一起
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');
如果使用jQuery, 尺寸插件是非常好的,并允许你指定你想要的。
例如
相对位置,绝对位置,无填充的绝对位置,填充…
它继续,我们只是说有很多你可以用它做。
再加上使用jQuery的好处是它的轻量级文件大小和易于使用,你不会在没有它之后回到JavaScript。
我已经采取了@ meouw的答案,在允许边界的clientLeft中添加,然后创build了三个版本:
getAbsoluteOffsetFromBody – 类似于@ meouw's,它获得相对于文档body或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 – 我注意到至less有一个可疑的代码在getStyle这应该是罚款,假设浏览器的行为,但还没有testing其余的。
这是我创build的最好的代码(在iframe中也是如此,不像jQuery的offset())。 似乎webkit有一点不同的行为。
基于评论的评论:
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,这可能是一个简单的解决scheme:
<script> var el = $("#element"); var position = el.position(); console.log( "left: " + position.left + ", top: " + position.top ); </script>
我find的最简洁的方法是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;
var els = document.getElementsByTagName("div"); var docEl = document.documentElement; for (var i = 0; i < els.length; i++) { var rect = els[i].getBoundingClientRect(); var rectTop = rect.top + window.pageYOffset - docEl.clientTop; var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft; els[i].innerHTML = "<b>" + rectLeft + ", " + rectTop + "</b>"; }
div { width: 100px; height: 100px; background-color: red; border: 1px solid black; } #rel { position: relative; left: 10px; top: 10px; } #abs { position: absolute; top: 250px; left: 250px; }
<div id="rel"></div> <div id="abs"></div> <div></div>
小与小的区别
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
我这样做是为了与旧浏览器交叉兼容。
// 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
我成功地使用了Andy E的解决scheme来定位引导程序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"> <at: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');"); } }); }
希望这可以帮助别人,这个post帮了大忙。
只是以为我会把它扔到那里。
我还没有能够在旧版浏览器中testing它,但它在最新的前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()}; };
经过大量的研究和testing,这似乎工作
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 }; }
由于不同的浏览器以不同的方式呈现边框,边框,边距等。 我写了一个小函数来检索每个根元素中的特定元素的顶部和左侧位置,以精确的维度:
function getTop(root, offset) { var rootRect = root.getBoundingClientRect(); var offsetRect = offset.getBoundingClientRect(); return offsetRect.top - rootRect.top; }
要检索左侧位置,您必须返回:
return offsetRect.left - rootRect.left;
尽pipe在这么多答案的底部,这很可能会丢失,但这里的顶级解决scheme并不适合我。
据我所知,其他任何答案都没有帮助。
情况 :
在一个HTML5页面中,我有一个菜单是一个头部内的导航元素(不是头部,而是另一个元素中的头部)。
当用户滚动浏览器时,我希望导航能够保持在最前面,但是在此之前,头部是绝对定位的(所以我可以将它覆盖一些其他的东西)。
上面的解决scheme从来没有引发任何改变,因为.offsetTop不会改变,因为这是一个绝对定位的元素。 此外,.scrollTop属性只是最上面的元素的顶部…也就是说,总是0。
我使用这两个函数进行的任何testing(和getBoundingClientRect结果相同)都不会告诉我导航栏的顶部是否滚动到可见页面的顶部(同样,在控制台中报告,它们在滚动时保持相同的数字发生)。
解
我的解决scheme正在利用
window.visualViewport.pageTop
pageTop属性的值反映了屏幕的可见部分,因此允许我跟踪元素参考可见区域的边界的位置。
也许没必要说,随时随地处理滚动我希望使用此解决scheme编程方式响应滚动元素的移动。
希望它可以帮助别人。