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


当前回答

这是我所创建的最好的代码(与jQuery的offset()不同,也可以在iframes中使用)。看起来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 };
}

其他回答

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

offsetLeft
offsetTop

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

IE和FF3具有

clientLeft
clientTop

这些财产不太常见,它们使用其父工作区指定元素位置(填充区是工作区的一部分,但边界和边距不是)。

更新:

递归方法(在我以前的答案中)创建了许多调用堆栈。在这种情况下,我们可以使用while循环来避免递归:

/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    let top = 0, left = 0;
    while (el !== null) {
        top += el.offsetTop;
        left += el.offsetLeft;
        el = el.offsetParent;
    }
    return {top, left};
}

旧答案:

/**
 *
 * @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;
}

感谢Thinkingtiff的回答,这只是另一个版本。

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

如果您使用jQuery,这可能是一个简单的解决方案:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>

虽然这很可能会在这么多答案的底部丢失,但这里的顶级解决方案并不适合我。据我所知,其他答案都没有帮助。情况:在HTML5页面中,我有一个菜单,它是页眉中的导航元素(不是页眉,而是另一个元素中的页眉)。我希望一旦用户滚动到顶部,导航就一直保持在顶部,但在此之前,标题是绝对定位的(所以我可以让它稍微覆盖一些其他内容)。上述解决方案从未触发过更改,因为.offsetTop不会更改,因为这是一个绝对定位的元素。此外,scrollTop属性只是最顶部元素的顶部。。。也就是说0并且总是0。我使用这两个(以及getBoundingClientRect结果)执行的任何测试都不会告诉我导航栏的顶部是否曾滚动到可查看页面的顶部(再次,正如控制台中所报告的那样,它们只是在滚动时保持相同的数字)。

解决方案我使用的解决方案

window.visualViewport.pageTop

pageTop属性的值反映了屏幕的可视部分,因此允许我跟踪元素相对于可视区域边界的位置。

也许没必要说,每当我处理滚动时,我都希望使用这个解决方案以编程方式响应正在滚动的元素的移动。希望它能帮助其他人。重要提示:这似乎在Chrome和Opera中有效,在Firefox(6-2018)中肯定不行。。。在Firefox支持visualViewport之前,我建议不要使用这种方法(我希望他们很快会使用……这比其他方法更有意义)。更新:请注意此解决方案。虽然我仍然发现我发现的对于“……以编程方式响应滚动元素的移动”的情况非常有用。我遇到的问题的更好解决方案是使用CSS在元素上设置位置:粘滞。使用sticky,您可以在不使用javascript的情况下让一个元素保持在顶部(注意:有时这不会像将元素更改为固定的那样有效,但对于大多数情况,sticky方法可能会更好)更新01:所以我意识到,对于不同的页面,我需要在一个稍微复杂的滚动设置中检测元素的位置(视差加上作为消息一部分滚动经过的元素)。在这种情况下,我意识到以下内容提供了我用来确定何时做某事的价值:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

希望这个答案现在更有用。