题 检索HTML元素的位置(X,Y)


我想知道如何获取HTML元素的X和Y位置,如 img 和 div 在JavaScript中。


1012
2018-01-14 09:35


起源


相对于什么? - AnthonyWJones
我一直在使用这7行代码,这些代码适用于所有浏览器,在ie5,6,7中有差异(我不记得有任何proboem ......可能是doc类型)... quirksmode.org/js/findpos.html 这么多年来我一直在使用它。可能是sombody可以指出缺陷,如果有的话。 - Jayapal Chandran
@AnthonyWJones,我想你需要迂腐的乐趣,但很明显,因为它总是在未指定时,OP指的是最一般的情况,或者指的是浏览器的窗口坐标。 - Motes
@AndyE的回答是一个明显的赢家 - 请你标记接受的答案,以便其他人不必阅读其他10个答案就可以了解答案吗? - mindplay.dk
@Mote,不,这不是那么明显。抛开推论,主观性和错误的公理。它可以是相对于视口或页面顶部(也就是document.documentElement)。 - Andre Figueiredo


答案:


正确的方法是使用 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>');

1308
2017-07-09 14:06



一个 关于JS坐标的非常有趣的文章。这篇文章在SO上没有提到,应该...... - Ring Ø
不起作用......由于身体的8px边距,它在垂直和水平方向上都是8像素。 Meouw的解决方案非常有效。如果你想我有一个小测试来证明这个问题。 - CpnCrunch
实际上,我认为这取决于你真正希望获得的协调。这个问题有点含糊不清。如果你只想要相对于视口或相对于body元素的coords,你的答案是正确的,但是如果你想要元素的绝对位置(我想象的是大多数人想要的),这对你没有帮助。 meouw的答案也不会给你这个,除非你删除'-scrollLeft'和'-scrollTop'位。 - CpnCrunch
@CpnCrunch:我明白你的意思了;我没有意识到你指的是我答案的后半部分。当主体具有边缘时,其边界框将偏移每个相应侧的像素数。在这种情况下,您还必须从身体坐标中减去计算的边距样式。值得注意的是,CSS重置会删除边距 <body>但是。 - Andy E
这回答了解决方案 elemRect.top - bodyRect.top 和类似的 elemRect.left - bodyRect.left 幸运的是,容忍变焦。当Android Chrome中的窗口缩放时,jQuery的offset()给出不同的结果。 jQuery投降了 offset(): 当用户缩放页面时,尺寸可能不正确;浏览器不公开API来检测这种情况。 使用此答案解决方案,您不需要API来检测缩放条件。 - Timo Kähkönen


这些库会花费一些时间来获得元素的准确偏移量。
这是一个简单的功能,可以在我尝试的每种情况下完成工作。

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; 

257
2018-01-14 10:04



更改:el = el.parentNode to:el = el.offsetParent;它现在似乎适用于嵌套的iframe ......我在想这是你的意图吗? - Adam
此解决方案不完整。尝试在div上放一个粗边框并将其嵌套几次。在任何版本的Firefox(2-5)中,它都会受到边框宽度的限制(即使在标准兼容模式下)。 - ck_
有没有一种更清洁的方法,比如el.totalOffsetLeft和totalOffsetTop函数? jQuery肯定有这个选项,但遗憾的是没有官方方法,我们需要等待DOM4吗?我正在构建一个HTML5画布应用程序,所以我认为最好的解决方案是在iframe中插入canvas元素,这样当我们点击元素时,我可以获得clientX和clientY的真实坐标。 - baptx
那么,@ Adam和meouw,你是说第一个代码块错了吗?那为什么不完全删除它? (多年来这个问题看到了很多观众;如果他们错了,可能会很好的删除?) - Arjan
这不适用于转换后的元素。 - Alex


这对我有用(从最高投票答案修改):

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

使用这个我们可以打电话

getOffset(element).left

要么

getOffset(element).top

140
2018-01-29 18:46



很好,很简单。为什么没有更多人喜欢这种解决方案? - Scott Biggs
当元素被放入时,只有这个解决方案适合我 div 以css为中心 top:50%, left:50%; transform:translate(-50%, -50%); ... 优秀。同意whit @ScottBiggs问题。逻辑是寻求简单。 - nelek
也许它不是胜利者,因为它与Andy E的解决方案相同,但在旧浏览器<IE9中不起作用 - niltoid
很有帮助!!谢了哥们。 - Omar AlMA3lOl
这是最好的解决方案。 - RubyFanatic


如果页面包含 - 至少 - 任何“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];
};


29
2017-08-12 20:14



与其他解决方案一样,即使使用FF 24.4,当边界宽度作为定位布局的一部分存在时,上述代码也不起作用。 - rob
谢谢你的这个功能。它适用于我需要的东西。 - HotFudgeSunday
你是一个救命的人。我现在正在研究一些非常深的GWT错误,并将其放入JSNI方法中解决了我所有的问题! - Will Byrne


您可以添加两个属性 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 和 .lefthttp://jsfiddle.net/ThinkingStiff/3G7EZ/


28
2018-01-14 08:57



修改 Element.prototype 通常被认为是 一个坏主意。这导致很难维护代码。此外,此代码不考虑滚动。 - Jared Forsyth


大多数浏览器上的HTML元素都有: -

offsetLeft
offsetTop

这些指定了元素相对于具有布局的最近父元素的位置。通常可以通过offsetParent属性访问此父级。

IE和FF3都有

clientLeft
clientTop

这些属性不太常见,它们使用其父客户区指定元素位置(填充区域是客户区域的一部分,但边界和边距不是)。


25
2018-01-14 09:43





要有效地检索相对于页面的位置,而不使用递归函数:(也包括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;

21
2017-07-26 01:49



包括所有重要的scrollTop / scrollLeft使得这个答案更加正确。 - scunliffe


这样的事情,通过传递元素的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');

18
2018-05-22 13:09





使用JavaScript框架可以提供更好的服务,该框架具有以独立于浏览器的方式返回此类信息(以及更多!)的功能。以下是一些:

使用这些框架,您可以执行以下操作: $('id-of-img').top 获得图像的y像素坐标。


17
2018-01-14 09:47



@Costa他们都使用这些功能,虽然这是一个不断发展的领域,因为不同的浏览器符合规范。这么多代码都涉及“修复”出错的事情。你真的应该看一下源代码。 - Shalom Craimer
@scraimer:jQuery和YUI是 不是框架!这些是 图书馆!这是不一样的。引用 jquery.com: “jQuery是一个快速,小巧,功能丰富的JavaScript 图书馆“。 引用 yuilibrary.com (你也可以在URL中看到“魔术”一词......): “YUI是一个免费的开源JavaScript和CSS 图书馆 用于构建丰富的交互式Web应用程序。“ - Sk8erPeter
所以你应该只为这个简单的任务使用庞大的库?不必要。我讨厌每次我想用js做一些事情,我都会得到这些jQuery解决方案。 jQuery不是JS! - Opptatt Jobber
@OpptattJobber我同意...... JQuery不是javascript。它依赖于Javascript,但它完全是一种不同的编程语言。 - Nick Manning
@NickManning它不是一种新语言,它是DOM的抽象层,它消除了必须直接在代码中编写兼容性和性能变通方法。如果你不使用jQuery,你应该使用某种类型的抽象层。 - ginman


jQuery的 。抵消() 将获取第一个元素的当前坐标,或者在匹配元素集中相对于文档设置每个元素的坐标。


14
2017-08-18 14:43



出于某种原因,与其他浏览器相比,它在IE中没有给出相同的结果。我认为在IE中它是相对于窗口的位置,所以如果你滚动,你将在IE中获得与其他人不同的结果 - Abdul Rahim Haddad
offset()被缩放混淆,至少在Android Chrome中是如此,所以它没用。 stackoverflow.com/a/11396681/1691517显示缩放容忍方式。 - Timo Kähkönen