如何获得元素相对于浏览器视口的顶部位置?


173

我想获取元素相对于浏览器视口(显示页面的视口,而不是整个页面)的位置。如何用JavaScript完成?

非常感谢


2
我认为这个问题类似于stackoverflow.com/questions/211703/…,它有一个非常好的解决方案。
雅各布·朗格

1
@JakobRunge,那是2013年的“好”吗?
Iulian Onofrei

1
考虑接受一个解决方案。
Iulian Onofrei

Answers:


305

现有答案现在已过时。本机getBoundingClientRect()方法已经存在了很长一段时间,并且可以完全满足问题的要求。另外,所有浏览器(似乎包括IE 5)都支持它。

MDN页面

返回的值是一个TextRectangle对象,该对象包含只读的left,top,right和bottom属性,以像素为单位描述边框,以左上角相对于视口的左上角

您可以这样使用它:

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;

3
使用浏览器缩放(Android Chrome)时,这可能无法正常工作。@rism的解决方案(请参见下文)在这种情况下有效
Dmitry

4
在大多数情况下都很好,但是它假定元素不在嵌入式iframe中,对吗?问题是询问浏览器的相对窗口。el.getBoundingClientRect()将返回相对于iframe的窗口,而不是浏览器窗口。
cakidnyc

6
问题是询问浏览器的相对窗口。
德米特里·德沃尼科夫

2
@Denilson getBoundingClientRect().top不在我的IE11中,它返回0。您有解决方案吗?
阿里夫

@Arif:对不起,但我无法重现您的问题。我在IE11上对此进行了测试,但仍得到了结果:codepen.io/denilsonsa/pen/ypqyXj
DenilsonSáMaia

57

就我而言,为了安全起见,我将window.scroll添加到公式中:

var element = document.getElementById('myElement');
var topPos = element.getBoundingClientRect().top + window.scrollY;
var leftPos = element.getBoundingClientRect().left + window.scrollX;

这使我可以获取元素在文档中的真实相对位置,即使它已经滚动了。


2
您不是应该添加滚动位置而不是减去滚动位置吗?
Iulian Onofrei

我支持答案,但@lulian Onofrei正确。请编辑。
pmrotule

@Fabio getBoundingClientRect().top不在我的IE11中,它返回0。您有解决方案吗?
Arif

1
@Arif window.scrollY || window.pageYOffset可能会改善支持
Fabian von Ellerts

@FabianvonEllerts :)
Arif

15

编辑: 添加一些代码以进行页面滚动。

function findPos(id) {
    var node = document.getElementById(id);     
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
        } while (node = node.offsetParent);

        alert(curtop - curtopscroll);
    }
}

id参数是您想要其偏移量的元素的id。改编自quirksmode帖子


1
感谢您的回答,但我认为您误解了我的问题,我知道如何相对于页面获取元素的顶部,我想做的就是获取相对于“视口”(即浏览器窗口)的位置,而不是文档)
Waleed Eissa

抱歉,您对“视口”的使用使我震惊。因此,您是说要考虑浏览器镶边,即书签工具栏,位置栏等?
德里克·斯温利

不,只是查看页面的窗口。如果滚动页面,则此页面将与文档顶部不同,否则页面相同。
Waleed Eissa

哦,我知道了。不知道该怎么做...如果我提出了一些建议,将会编辑我的答案。
德里克·斯威利

我在上面编写了一些丑陋的代码,但是它可以工作...使用offsetParent.scrollTop
Derek Swingley,2009年

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

这似乎是计算从文件的顶部,而不是视
斯科特伦纳德


5

jQuery非常优雅地实现了这一点。如果您查看jQuery的源代码offset,就会发现这基本上是它的实现方式:

var rect = elem.getBoundingClientRect();
var win = elem.ownerDocument.defaultView;

return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
};

2

页面上的函数将返回一个矩形,其中包含相对于浏览器视口的传递元素的顶部,左侧,高度和宽度坐标。

    localToGlobal: function( _el ) {
       var target = _el,
       target_width = target.offsetWidth,
       target_height = target.offsetHeight,
       target_left = target.offsetLeft,
       target_top = target.offsetTop,
       gleft = 0,
       gtop = 0,
       rect = {};

       var moonwalk = function( _parent ) {
        if (!!_parent) {
            gleft += _parent.offsetLeft;
            gtop += _parent.offsetTop;
            moonwalk( _parent.offsetParent );
        } else {
            return rect = {
            top: target.offsetTop + gtop,
            left: target.offsetLeft + gleft,
            bottom: (target.offsetTop + gtop) + target_height,
            right: (target.offsetLeft + gleft) + target_width
            };
        }
    };
        moonwalk( target.offsetParent );
        return rect;
}

2
function inViewport(element) {
    let bounds = element.getBoundingClientRect();
    let viewWidth = document.documentElement.clientWidth;
    let viewHeight = document.documentElement.clientHeight;

    if (bounds['left'] < 0) return false;
    if (bounds['top'] < 0) return false;
    if (bounds['right'] > viewWidth) return false;
    if (bounds['bottom'] > viewHeight) return false;

    return true;
}

资源


1

感谢所有的答案。似乎Prototype已经具有执行此操作的功能(page()函数)。通过查看该函数的源代码,我发现它首先计算相对于页面(即文档顶部)的元素偏移位置,然后从中减去scrollTop。有关更多详细信息,请参见原型的源代码。


好决定。最好使用主要的库之一,因为它们更可能在浏览器中产生相同的结果。如果您好奇,请查看我的回答。那里的代码将执行此操作,但是我不知道它将如何在所有浏览器中使用。
德里克·斯温利

1

我假设btn1网页中存在一个id为的元素,并且还包括jQuery。这已在所有现代的Chrome,FireFox,IE> = 9和Edge的浏览器中使用。jQuery仅用于确定相对于文档的位置。

var screenRelativeTop =  $("#btn1").offset().top - (window.scrollY || 
                                            window.pageYOffset || document.body.scrollTop);

var screenRelativeLeft =  $("#btn1").offset().left - (window.scrollX ||
                                           window.pageXOffset || document.body.scrollLeft);

1
jQuery是JavaScript。我相信您的意思是“它不是100%香草/纯JS”。
hungerstar '16

是的,这就是我的意思。
Sunil 2016年

1

有时,getBoundingClientRect()对于IE,对象的属性值显示为0。在这种情况下,您必须设置display = 'block'元素。您可以对所有浏览器使用以下代码来获取偏移量。

扩展jQuery功能:

(function($) {
    jQuery.fn.weOffset = function () {
        var de = document.documentElement;
        $(this).css("display", "block");
        var box = $(this).get(0).getBoundingClientRect();
        var top = box.top + window.pageYOffset - de.clientTop;
        var left = box.left + window.pageXOffset - de.clientLeft;
        return { top: top, left: left };
    };
}(jQuery));

用 :

var elementOffset = $("#" + elementId).weOffset();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.