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

1418 html javascript css dom position

我想知道如何获得HTML元素的X和Y位置,例如imgdivJavaScript.

And*_*y E 1672

正确的方法是使用element.getBoundingClientRect():

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
Run Code Online (Sandbox Code Playgroud)

Internet Explorer已经支持这个,因为只要你可能关心它,它最终在CSSOM Views中被标准化.所有其他浏览器很久以前就采用了它.

某些浏览器还返回高度和宽度属性,但这不是标准的.如果您担心较旧的浏览器兼容性,请查看此答案的修订版,以获得优化的降级实现.

返回的值element.getBoundingClientRect()相对于视口.如果您需要它相对于另一个元素,只需从另一个元素中减去一个矩形:

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');
Run Code Online (Sandbox Code Playgroud)

  • 一篇[关于JS坐标的非常有趣的文章](http://javascript.info/tutorial/coordinates).这篇文章在SO上没有提到,应该...... (127认同)
  • `BoundingClientRect` 在滚动时发生变化 (15认同)
  • 不起作用......它是垂直和水平的8像素,因为身体的8px边距.Meouw的解决方案完美无缺.如果你想我有一个小测试来证明这个问题. (5认同)
  • @CpnCrunch:我明白你的意思了; 我没有意识到你指的是我答案的后半部分.当主体具有边缘时,其边界框将偏移每个相应侧的像素数.在这种情况下,您还必须从身体坐标中减去计算的边距样式.值得注意的是,CSS重置会从"<body>"中删除边距. (4认同)
  • 实际上,我认为这取决于您实际想要获得的帮助。这个问题有点模棱两可。如果您只想要相对于视口或相对于body元素的坐标,那么您的答案是正确的,但是在您想要元素的绝对位置的情况下,这无济于事(我想这是大多数人想要的) 。除非您删除“ -scrollLeft”和“ -scrollTop”位,否则喵的答案也不会给您任何帮助。 (2认同)

meo*_*ouw 310

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

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; 
Run Code Online (Sandbox Code Playgroud)

  • 更改:el = el.parentNode to:el = el.offsetParent; 它现在似乎适用于嵌套的iframe ...我在想这是你的意图吗? (14认同)
  • 这个解决方案不完整.尝试在div上放一个粗边框并将其嵌套几次.在任何版本的Firefox(2-5)中,它都会受到边框宽度的影响(即使在标准兼容模式下). (3认同)
  • 是不是有更清洁的方法,像el.totalOffsetLeft和totalOffsetTop函数?jQuery肯定有这个选项,但遗憾的是没有官方方法,我们需要等待DOM4吗?我正在构建一个HTML5画布应用程序,所以我认为最好的解决方案是在iframe中插入canvas元素,这样当我们点击元素时,我可以获得clientX和clientY的真实坐标. (3认同)
  • 这不适用于转换后的元素. (3认同)

Ada*_*ant 212

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

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}
Run Code Online (Sandbox Code Playgroud)

使用这个我们可以打电话

getOffset(element).left
Run Code Online (Sandbox Code Playgroud)

要么

getOffset(element).top
Run Code Online (Sandbox Code Playgroud)

  • 也许它不是胜利者,因为它与Andy E的解决方案相同,但在旧浏览器<IE9中不起作用 (3认同)
  • 如果该元素存在于许多嵌套的可滚​​动元素中怎么办?我认为您需要递归地考虑每个父元素的scrollLeft/scrollTop? (3认同)
  • `left:rect.left + window.scrollX +(rect.width / 2),top:rect.top + window.scrollY +(rect.height / 2)`将返回元素的中间位置 (2认同)

Amj*_*d K 56

如果你想只在javascript中完成它.比这里有一个衬里.它的简单易于使用getBoundingClientRect()

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
Run Code Online (Sandbox Code Playgroud)

第一行将返回offsetLeft,表示相对于文档的X.

并且第二行将返回offsetTop, 表示Y相对于文档

getBoundingClientRect()是一个javascript函数,它返回元素相对于窗口视口的位置.


Ant*_*nes 42

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

offsetLeft
offsetTop
Run Code Online (Sandbox Code Playgroud)

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

IE和FF3都有

clientLeft
clientTop
Run Code Online (Sandbox Code Playgroud)

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


小智 35

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

Run Code Online (Sandbox Code Playgroud)


Thi*_*iff 35

您可以添加两个属性以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 );
    }
} );
Run Code Online (Sandbox Code Playgroud)

这被称为:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;
Run Code Online (Sandbox Code Playgroud)

这里的比较结果以jQuery的演示offset().top.left:http://jsfiddle.net/ThinkingStiff/3G7EZ/

  • 修改`Element.prototype`通常被认为是一个坏主意*.这导致很难维护代码.此外,此代码不考虑滚动. (11认同)

Abd*_*dad 22

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


Phi*_*ipp 21

这是一个现代的 1-liner,使用 vanilla JS 递归地迭代element.offsetTopand element.offsetParent

功能:

getTop = el => el.offsetTop + (el.offsetParent && getTop(el.offsetParent))
Run Code Online (Sandbox Code Playgroud)

用法:

const el = document.querySelector('#div_id');
const elTop = getTop(el)
Run Code Online (Sandbox Code Playgroud)

优势:

无论当前滚动位置如何,始终返回绝对垂直偏移。


传统语法:

function getTop(el) {
  return el.offsetTop + (el.offsetParent && getTop(el.offsetParent));
}
Run Code Online (Sandbox Code Playgroud)


Ali*_*eza 19

这样的事情,通过传递元素的ID,它将返回左侧或顶部,我们也可以组合它们:

1)找到左边

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');
Run Code Online (Sandbox Code Playgroud)

2)找到顶部

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');
Run Code Online (Sandbox Code Playgroud)

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');
Run Code Online (Sandbox Code Playgroud)


Sha*_*mer 17

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

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

  • 所以你应该只为这个简单的任务使用庞大的库?不必要.我讨厌每次我想用js做一些事情,我都会得到这些jQuery解决方案.jQuery不是JS! (27认同)
  • @scraimer:jQuery和YUI是**NOT frameworks**!!! 这些是**库**!这是不一样的.引用http://jquery.com/:_"jQuery是一个快速,小巧,功能丰富的JavaScript**库**."_引用http://yuilibrary.com/(你可以看到"魔术"一词在URL中...):_"YUI是一个免费的,开源的JavaScript和CSS**库**,用于构建丰富的交互式Web应用程序."_ (18认同)
  • @NickManning它不是一种新语言,它是DOM的抽象层,它消除了必须直接在代码中编写兼容性和性能变通方法.如果你不使用jQuery,你应该使用某种类型的抽象层. (5认同)
  • @Costa他们都使用这些功能,虽然这是一个不断发展的领域,因为不同的浏览器与规范不同.这么多代码都涉及"修复"出错的事情.你真的应该看一下源代码. (2认同)

aka*_*ppi 14

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


Văn*_*yết 12

/**
 *
 * @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;
}
Run Code Online (Sandbox Code Playgroud)

感谢ThinkingStiff答案,这只是另一个版本。


Jam*_*rke 10

我接受了@meouw的回答,在允许边框的clientLeft中添加了,然后创建了三个版本:

getAbsoluteOffsetFromBody - 类似于@meouw's,它获取相对于文档的body或html元素的绝对位置(取决于quirks模式)

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 };
}
Run Code Online (Sandbox Code Playgroud)

如果你仍然遇到问题,尤其是滚动问题,可以尝试查看http://www.greywyvern.com/?post=331 - 我注意到getStyle中至少有一段有问题的代码,假设浏览器的行为应该没问题,但还没有测试其余的.


Joh*_*hn_ 8

如果使用jQuery,维度插件非常好,并允许您准确指定您想要的.

例如

相对位置,绝对位置,无填充的绝对位置,带衬垫......

它继续,让我们说你可以做很多事情.

此外,使用jQuery的好处是它的文件很轻,易于使用,之后如果没有它,你就不会再回到JavaScript了.


Ada*_*ani 8

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

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


Ron*_*ter 7

这是我设法创建的最好的代码(也可以在iframe中工作,与jQuery的offset()不同).似乎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 };
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您需要 [`jQuery`](http://api.jquery.com/jQuery.browser/) 才能使用 `$.browser.webkit`;您需要使用“navigator.userAgent”来对纯“JavaScript”执行相同的操作。 (2认同)
  • $ .browser在最新版本的jQuery中不再可用 (2认同)

Kin*_*der 7

小与小的区别

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 };
}
Run Code Online (Sandbox Code Playgroud)

查看示例坐标:http: //javascript.info/tutorial/coordinates


Jam*_*gne 6

我发现最干净的方法是jQuery使用的技术的简化版本offset.与其他一些答案类似,它始于getBoundingClientRect; 然后使用windowdocumentElement调整滚动位置以及边距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;
Run Code Online (Sandbox Code Playgroud)

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>";
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
<div id="rel"></div>
<div id="abs"></div>
<div></div>
Run Code Online (Sandbox Code Playgroud)


MER*_*MER 6

虽然这很可能会在这么多答案的底部丢失,但这里的最佳解决方案对我不起作用。
据我所知,其他任何答案都没有帮助。

情况
在 HTML5 页面中,我有一个菜单,它是标题中的导航元素(不是标题,而是另一个元素中的标题)。
我希望导航在用户滚动到它时粘在顶部,但在此之前,标题是绝对定位的(所以我可以让它稍微覆盖其他东西)。
上面的解决方案从未触发更改,因为 .offsetTop 不会更改,因为这是一个绝对定位的元素。此外 .scrollTop 属性只是最顶部元素的顶部......也就是说 0 并且始终为 0。
我使用这两个(与 getBoundingClientRect 结果相同)执行的任何测试都不会告诉我导航栏的顶部是否曾经滚动到可查看页面的顶部(同样,如控制台中所报告的那样,它们只是在滚动时保持相同的数字发生了)。

解决
方案我的解决方案是利用

window.visualViewport.pageTop
Run Code Online (Sandbox Code Playgroud)

pageTop 属性的值反映了屏幕的可查看部分,因此允许我根据可查看区域的边界跟踪元素所在的位置。

可能没有必要说,每当我处理滚动时,我都希望使用此解决方案以编程方式响应正在滚动的元素的移动。
希望它可以帮助别人。
重要说明:这似乎目前在 Chrome 和 Opera 中有效,绝对不能在 Firefox (6-2018) 中使用......直到 Firefox 支持visualViewport 我建议不要使用这种方法,(我希望他们很快这样做......它做了很多比其他的更有意义)。


更新:
只是关于此解决方案的说明。
虽然我仍然发现我发现的对于“......以编程方式响应滚动元素的移动”的情况非常有价值。适用。我遇到的问题的更好解决方案是使用 CSS 来设置position:sticky在元素上。使用粘性,您可以在不使用 javascript 的情况下让元素保持在顶部(注意:有时这不会像将元素更改为固定那样有效,但对于大多数用途,粘性方法可能会更好)

UPDATE01:
所以我意识到对于不同的页面,我有一个要求,我需要在稍微复杂的滚动设置中检测元素的位置(视差加上作为消息一部分滚动过去的元素)。在那个场景中,我意识到以下提供了我用来确定何时做某事的价值:

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

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


Kev*_* K. 6

要获得元素的总偏移量,您可以递归地总结所有父偏移量:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}
Run Code Online (Sandbox Code Playgroud)

使用此实用程序函数,dom 元素的总顶部偏移为:

el.offsetTop + getParentOffsets(el);
Run Code Online (Sandbox Code Playgroud)


Boj*_*man 5

我是这样做的,因此它与旧浏览器交叉兼容.

// 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;
    }
Run Code Online (Sandbox Code Playgroud)

有关JavaScript中坐标的更多信息,请访问:http://javascript.info/tutorial/coordinates


小智 5

    
Run Code Online (Sandbox Code Playgroud)
HTML program to show (x, y) of an
element by dragging mouse over it  you just copied it and use it on your own 
<!DOCTYPE html>
<html>
    <head>
        <title>
            position of an element
        </title>
        
        <!-- scropt to get position -->
        <script type = "text/javascript">
            function getPositionXY(element) {
                var rect = element.getBoundingClientRect();
                document.getElementById('text').innerHTML
                = 'X: ' + rect.x + '<br>' + 'Y: ' + rect.y;
            }
        </script>
    </head>
    
    <body>
        <p>Move the mouse over the text</p>
        
        <div onmouseover = "getPositionXY(this)">
            Position:
            <p id = 'text'></p>
        </div>
    
    </body>
</html>                 
Run Code Online (Sandbox Code Playgroud)


小智 5

我可以只是喜欢element.offsetLeftelement.offsetTop。例子 : document.getElementById('profileImg').offsetLeft