JS中获取 DOM 元素的绝对位置实例详解
在操作页面滚动和动画时经常会获取DOM元素的绝对位置,例如本文左侧的悬浮导航,当页面滚动到它以前会正常地渲染到文档流中,当页面滚动超过了它的位置,就会始终悬浮在左侧。
本文会详述各种获取DOM元素绝对位置的方法以及对应的兼容性。关于如何获取DOM元素高度和滚动高度,请参考视口的宽高与滚动高度一文。
概述
这些是本文涉及的API对应的文档和标准,供查阅:
API | 用途 | 文档 | 标准 |
---|---|---|---|
offsetTop | 相对定位容器的位置 | MDN | CSSOMViewModule |
clientTop | 上边框宽度 | MDN | CSSOMViewModule |
.getBoundingClientRect() | 元素大小和相对视口的位置 | MDN | CSSOMViewModule |
.getClientRects() | 所有子CSS盒子的大小和位置 | MDN | CSSOMViewModule |
.getComputedStyle() | 应用所有样式表和计算之后的CSS属性 | MDN | DOMLevel2Style CSSOM |
offsetTop/offsetLeft
HTMLElement.offsetTop用来获取当前元素(不包括上边框)相对于定位容器(positioningcontainer)的位置。也就是说,
如果所有祖先元素都是静态定位position:static;(这是默认的情况),offsetTop表示与文档最上方的高度差(文档最上方可能已经滚出视口,这个高度可能大于视口高度)。
如果存在绝对定位的祖先元素position:absolute/fixed,offsetTop就会相对于这个元素。因此为了获取相对于文档最上方的高度差,需要递归地调用:
functiongetOffsetTop(el){ returnel.offsetParent ?el.offsetTop+getOffsetTop(el.offsetParent) :el.offsetTop }
el.offsetParent是当前元素的定位容器(positioningcontainer),如果当前元素没有绝对定位的祖先节点,这个属性的值就是null。
兼容性和限制:几乎所有浏览器都支持该属性。如果元素被隐藏它的值就是0,但在IE9下没有影响。
clientTop/clientLeft
不要被名字误导,Element.clientTop是指当前元素的上边框的宽度的整数值。总是等于getComputedStyle()返回的border-top-width属性的四舍五入为整数后的值。
为什么呢?在DOM术语中,client总是指除边框(border)外的渲染盒子(内边距+内容大小)。offset总是指包含边框的渲染盒子(边框+内边距+内容大小),clientTop即为这两者的Top之差,即边框宽度。盒子的概念请参考:CSSDisplay属性与盒模型
兼容性和限制:同offsetTop/offsetLeft
.getBoundingClientRect()
Element.getBoundingClientRect()用于获取元素的大小,以及相对于视口(viewport)的位置,返回一个DOMRect对象。
>document.querySelector('span').getBoundingClientRect() DOMRect{x:2.890625,y:218.890625,width:1264,height:110,top:218.890625,…} bottom:328.890625 height:110 left:2.890625 right:1266.890625 top:218.890625 width:1264 x:2.890625 y:218.890625
如果要获取相对于文档左上角的位置,需要在上述top和left的基础上再加滚动位置。如下代码来自MDN,可兼容几乎所有浏览器:
//ForscrollX (((t=document.documentElement)||(t=document.body.parentNode)) &&typeoft.scrollLeft=='number'?t:document.body).scrollLeft //ForscrollY (((t=document.documentElement)||(t=document.body.parentNode)) &&typeoft.scrollTop=='number'?t:document.body).scrollTop
兼容性和限制:同样是CSSOMViewModule的特性,但几乎兼容所有浏览器,可参考
https://caniuse.com/#feat=getboundingclientrectIE下窗口的左上角可能不是0,0,在IE9可以这样把它设置为0,0:
.getClientRects()
Element.getClientRects()用来获得DOM元素中的所有CSS盒模型对应的DOMRect组成的集合。
如果是一个块级元素,返回的集合中应该只有一个元素,即这个块的大小和位置。但如果是一个行内元素(或者SVG内的元素),则会返回其中每个CSS盒子。比如一个普通的被默认折行的:
>document.querySelector('span').getClientRects() DOMRectList{0:DOMRect,1:DOMRect,2:DOMRect,length:5} 0:DOMRect{x:2.890625,y:262.890625,width:1264,height:22,top:262.890625,…} 1:DOMRect{x:2.890625,y:284.890625,width:1264,height:22,top:284.890625,…} 2:DOMRect{x:2.890625,y:306.890625,width:768,height:22,top:306.890625,…}
这个有三行,其中第三行的长度不足一行,每次折行都形成了一个新的CSS盒子。
兼容性和限制:在IE8及以下会返回IE独有的TextRectangle对象(而不是ClientRect),这个对象不具有width和height属性,而且无法给它设置属性。参考:https://webplatform.github.io/docs/dom/HTMLElement/getClientRects/
.getComputedStyle()
Window.getComputedStyle()可以得到一个元素的所有计算后的CSS属性。对于简单的绝对定位元素,可以通过这个API返回的top,left等属性值获取元素的位置。例如:
letbtn=document.querySelector('#btn-scroll-up') let{top,left}=getComputedStyle(btn) console.log('top:',top,'left:',left)
.getComputedStyle()还有一个有用的用法,获取伪元素的大小和位置等样式信息:
//以下代码来自:https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle varh3=document.querySelector('h3'); varresult=getComputedStyle(h3,':after').content; console.log('thegeneratedcontentis:',result);//returns'rocks!'
兼容性和限制:.getComputedStyle()几乎兼容所有浏览器,可参考https://caniuse.com/#search=getComputedStyle。但它返回的值是CSS属性,用它获取绝对位置时要注意值的类型。例如left可能是13px这样的绝对值,也可能是auto这样的CSS关键字。
总结获取DOM元素相对于文档的位置,可以直接使用offsetTop;获取DOM元素相对于视口的位置,可以使用.getBoundingClientRect();获取SVG元素或行内元素的CSS盒子(比如用来做文本高亮时),可以使用.getClientRects();获取绝对定位元素、伪元素的渲染后CSS属性,可以使用.getComputedStyle()
总结
以上所述是小编给大家介绍的JS中获取DOM元素的绝对位置实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!