在操作頁面滾動和動畫時經常會獲取DOM 元素的絕對位置,例如本文左側的懸浮導航,當頁面滾動到它以前會正常地渲染到文檔流中,當頁面滾動超過了它的位置,就會永遠懸浮在左側。
API |
用途 |
文件 |
標準 |
##offsetTop | 相對定位容器的位置 | MDN | CSSOM View Module |
clientTop | 上邊框寬度 | MDN | CSSOM View Module |
.getBoundingClientRect() | 元素大小與相對視窗的位置 | MDN | CSSOM View Module |
.getClientRects() | 所有子CSS 盒子的大小和位置 | #MDN | CSSOM View Module |
.getComputedStyle() | 套用所有樣式表和計算之後的CSS 屬性 | MDN | DOM Level 2 Style CSSOM |
offsetTop/offsetLeft
HTMLElement.offsetTop 用來取得目前元素(不包含上方邊框)相對於定位容器(positioning container)的位置。也就是說,
如果所有祖先元素都是靜態定位position:static;
(這是預設的情況),offsetTop
表示與文件最上方的高度差(文檔最上方可能已經滾出視口,這個高度可能大於視口高度)。
如果存在絕對定位的祖先元素 position:absolute/fixed
,offsetTop
就會相對於這個元素。因此為了取得相對於文件最上方的高度差,需要遞歸地呼叫:
function getOffsetTop(el){
return el.offsetParent
? el.offsetTop + getOffsetTop(el.offsetParent)
: el.offsetTop
}
登入後複製
el.offsetParent
是目前元素的定位容器(positioning container),如果目前元素沒有絕對定位的祖先節點,這個屬性的值就是null
。
相容性與限制:幾乎所有瀏覽器都支援該屬性。如果元素被隱藏它的值就是 0,但在 IE9 下沒有影響。
clientTop/clientLeft
#不要被名字誤導,Element.clientTop 是指當前元素的上邊框的寬度的整數值。總是等於 getComputedStyle()
傳回的 border-top-width
屬性的四捨五入為整數後的值。
為什麼呢?在 DOM 術語中,client 總是指除邊框(border)外的渲染盒子(內邊距 內容大小)。 offset 總是指包含邊框的渲染盒子(邊框 內邊距 內容大小),clientTop
即為這兩者的 Top 之差,即邊框寬度。盒子的概念請參考:CSS Display 屬性與盒模型
相容性與限制:同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,可相容幾乎所有瀏覽器:
// For scrollX
(((t = document.documentElement) || (t = document.body.parentNode))
&& typeof t.scrollLeft == 'number' ? t : document.body).scrollLeft
// For scrollY
(((t = document.documentElement) || (t = document.body.parentNode))
&& typeof t.scrollTop == 'number' ? t : document.body).scrollTop
登入後複製
相容性與限制:同樣是CSSOM View Module 的特性,但幾乎相容於所有瀏覽器,可參考
# https://caniuse.com/#feat=getboundingclientrectIE 下視窗的左上角可能不是0,0,在IE9 可以這樣把它設定為0,0:
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
登入後複製
.getClientRects()
Element.getClientRects() 用來取得DOM 元素中的所有CSS 盒子模型對應的DOMRect 組成的集合。
如果是一個區塊級元素,在傳回的集合中應該只有一個元素,也就是這個區塊的大小和位置。但如果是一個行內元素(或 SVG 內的元素),則會傳回其中每個 CSS 盒子。例如一個普通的被預設折行的<span>
:
> 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, …}
登入後複製
這個<span>
有三行,其中第三行的長度不足一行,每次折行都形成了一個新的CSS 盒子。
相容性與限制:在IE8 及以下會回傳IE 獨有的TextRectangle
物件(而不是ClientRect
),這個物件不具有width
和height
屬性,而且無法為它設定屬性。參考:https://webplatform.github.io/docs/dom/HTMLElement/getClientRects/
.getComputedStyle()
Window. getComputedStyle() 可以得到一個元素的所有計算後的CSS 屬性。對於簡單的絕對定位元素,可以透過這個 API 傳回的 top
,left
等屬性值來取得元素的位置。例如:
let btn = 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
var h3 = document.querySelector('h3');
var result = getComputedStyle(h3, ':after').content;
console.log('the generated content is: ', result); // returns ' rocks!'
登入後複製
兼容性和限制:.getComputedStyle()
几乎兼容所有浏览器,可参考 https://caniuse.com/#search=getComputedStyle。但它返回的值是 CSS 属性,用它获取绝对位置时要注意值的类型。例如 left
可能是 13px
这样的绝对值,也可能是 auto
这样的 CSS 关键字。
总结 获取 DOM 元素相对于文档的位置,可以直接使用 offsetTop
; 获取 DOM 元素相对于视口的位置,可以使用 .getBoundingClientRect()
; 获取 SVG 元素或行内元素的 CSS 盒子(比如用来做文本高亮时),可以使用 .getClientRects()
; 获取绝对定位元素、伪元素的渲染后 CSS 属性,可以使用 .getComputedStyle()
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Angular4性能优化方法总结
jQuery+ajax动态操作表格tr td步骤详解