首页 文章

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

提问于
浏览
1139

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

24 回答

  • 1

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

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

  • 1418

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

    这里's a demo comparing the results to jQuery' s offset().top.lefthttp://jsfiddle.net/ThinkingStiff/3G7EZ/

  • 8

    小与小的区别

    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

  • 272

    我发现的最干净的方法是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;
    
    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>
    
  • 5

    这是我设法创建的最好的代码(也可以在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 };
    }
    
  • 14

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

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

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

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

    要检索左侧位置,您必须返回:

    return offsetRect.left - rootRect.left;
    
  • 9

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

    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

  • 21

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

    获取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
    
  • 7

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

    getAbsoluteOffsetFromBody - 类似于@meouw,它获取相对于文档的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 };
    }
    

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

  • 30

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

    这些库会花费一些时间来获得元素的准确偏移量 .
    在这里's a simple function that does the job in every circumstances that I'已经尝试过了 .

    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;
    
  • 174

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

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

    如果你想完成 only in javascript . 比这里的 one liners . 它的 simplereasy 使用getBoundingClientRect()

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

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

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

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

  • 17

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

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

  • 0

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

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

    使用这个我们可以打电话

    getOffset(element).left
    

    要么

    getOffset(element).top
    
  • 5

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

  • 7

    如果使用jQuery,dimensions plugin是非常好的,并允许您准确指定您想要的 .

    例如

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

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

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

  • 0

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

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

    Solution
    我的解决方案是利用

    window.visualViewport.pageTop
    

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

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

    UPDATE:
    关于此解决方案的说明 .
    虽然我仍然发现我发现的东西对于"...programmatically respond to movement of elements being scrolled."适用的情况非常有 Value . 我遇到的问题的更好解决方案是使用CSS在元素上设置position: sticky . 使用粘性你可以让一个元素保持在顶部而不使用javascript(注意:有时这不会像将元素更改为固定那样有效,但对于大多数用途,粘性方法可能会更好)

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

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

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

  • 4

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

    1) find left

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

    2) find top

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

    3) find left and top together

    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');
    
  • 1

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

    offsetLeft
    offsetTop
    

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

    IE和FF3都有

    clientLeft
    clientTop
    

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

  • 32

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

    // 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

相关问题