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

时间:2009-01-14 09:35:03

标签: javascript html css dom position

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

28 个答案:

答案 0 :(得分:1555)

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

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer已支持此功能,因为只要您可能关心它,并且最终在CSSOM Views中进行了标准化。所有其他浏览器都采用了它a long time ago

某些浏览器也会返回高度和宽度属性,但这是非标准的。如果您担心较旧的浏览器兼容性,请查看此答案的修订版,以了解优化的降级实施。

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

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

alert('Element is ' + offset + ' vertical pixels from <body>');

答案 1 :(得分:295)

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

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; 

答案 2 :(得分:198)

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

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

使用此我们可以致电

getOffset(element).left

getOffset(element).top

答案 3 :(得分:34)

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

答案 4 :(得分:34)

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

offsetLeft
offsetTop

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

IE和FF3

clientLeft
clientTop

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

答案 5 :(得分:32)

您可以向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/

答案 6 :(得分:23)

如果您只希望使用javascript 完成操作,则可以使用getBoundingClientRect()

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

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

第一行将返回offsetLeft说X相对于文档。

第二行将相对于文档返回offsetTop说Y。

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

答案 7 :(得分:21)

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

答案 8 :(得分:19)

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

答案 9 :(得分:16)

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

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

答案 10 :(得分:14)

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

答案 11 :(得分:10)

我已经采取了@ meouw的答案,添加到允许边框的clientLeft中,然后创建了三个版本:

getAbsoluteOffsetFromBody - 类似于@meouw&#39; 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 - 我注意到getStyle中至少有一段有问题的代码应该没问题,假设浏览器有行为,但是没有问题。完全测试了其余部分。

答案 12 :(得分:8)

如果使用jQuery,dimensions plugin非常好,并且允许您准确指定所需内容。

e.g。

相对位置,绝对位置,没有填充的绝对位置,带填充...

接下来,让我们说你可以做很多事情。

另外,使用jQuery的好处是它的文件大小轻松且易于使用,之后如果没有它,你就不会再回到JavaScript了。

答案 13 :(得分:7)

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

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

答案 14 :(得分: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 };
}

答案 15 :(得分: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 };
}

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

答案 16 :(得分:6)

我发现最干净的方法是jQuery&#39; 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;

&#13;
&#13;
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>";
}
&#13;
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;
}
&#13;
<div id="rel"></div>
<div id="abs"></div>
<div></div>
&#13;
&#13;
&#13;

答案 17 :(得分: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;
    }

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

答案 18 :(得分:4)

    
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>                 

答案 19 :(得分:3)

虽然很可能在这么多答案的底部丢失了,但这里的顶级解决方案并不适用于我。
据我所知,任何其他答案都没有帮助。

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

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

window.visualViewport.pageTop

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

可能没必要说,无论何时我正在处理滚动,我希望使用此解决方案以编程方式响应滚动元素的移动。
希望它可以帮助别人。
重要提示:This appears to work in Chrome and Opera currently & definitely not in Firefox (6-2018) ...在Firefox支持visualViewport之前我建议不要使用这种方法,(我希望他们能尽快完成......它比其他方法更有意义)。


更新:
关于此解决方案的说明。
虽然我仍然发现我发现的东西非常有价值,其中&#34; ...以编程方式响应滚动元素的移动。&#34;适用。我遇到问题的更好解决方案是使用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 = '';
  }

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

答案 20 :(得分:2)

我成功使用了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');");
        }
    });
}

希望这有助于某人,这篇文章有所帮助。

答案 21 :(得分:2)

要获取元素的总偏移量,您可以递归求和所有父偏移量:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

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

el.offsetTop + getParentOffsets(el);

答案 22 :(得分:2)

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

感谢ThinkingStiffthe answer,这只是它的另一个版本。

答案 23 :(得分:1)

经过大量研究和测试后,这似乎有效

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 };
}

请参阅http://jsbin.com/xuvovalifo/edit?html,js,output

答案 24 :(得分:1)

我以为我也会把它扔出去。
我无法在旧版浏览器中测试它,但它可以在前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()};
};

答案 25 :(得分:0)

由于不同的浏览器以不同的方式呈现边框,填充,边距等。我写了一个小函数来检索你想要的每个根元素中特定元素的顶部和左侧位置:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

要获取左侧位置,您必须返回:

    return offsetRect.left - rootRect.left;

答案 26 :(得分:0)

  

获取div相对于left和Top

的位置
  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 

答案 27 :(得分:0)

这很容易,因为在JS中只有两行:

var elem = document.getElementById("id");    
alert(elem.getBoundingClientRect());