[教學] 一次搞懂 clientHeight/clientWidth/offSetHeight/offsetWidth/scrollHeight/scrollWidth/scrollTop/scrollLeft 的區別
在JavaScript中,取得DOM元素的寬度或高度,可以利用clientHeight/clientWidth/offSetHeight/offsetWidth/scrollHeight/scrollWidth/scrollTop/scrollLeft…等屬性,這篇文章整理了不同屬性之間的區別以及應用。下次遇到時再也不會分不清楚了!
目錄
上面先放個示意圖方便對照著看,圖片來源:Determining the dimensions of elements - MDN
寬度/高度
關於元素的寬度和高度,有三組屬性可以使用,分別是offsetWidth
/offsetHeight
,clientWidth
/clientHeight
,及scrollWidth
/scrollHeight
。雖然名字很像,但是功用卻大不同!下面就讓我們來看看這三組屬性的差別。
注意:再計算寬度或高度之前,必須先問自己:邊界 (border) 及捲軸的寬度/高度需要被包含在內嗎?
-
offsetWidth
/offsetHeight
是「元素本身」的寬度/高度,並完整了包含了邊界、捲軸及padding。 -
clientWidth
/clientHeight
則是元素所包含的「子元素」的寬度/高度,其中包含了padding,但不包含邊界及捲軸。 -
scrollWidth
/scrollHeight
也是元素所包含的「子元素」的「完整」寬度和高度,其中包含了超出捲軸之外的部分的寬度與高度。在沒有捲軸的情況下,這個值就等於clientWidth
/clientHeight
。
相對位置
關於元素的相對位置,同樣也有三組屬性可以使用,分別是 offsetLeft
/offsetTop
,clientLeft
/clientTop
,及 scrollLeft
/scrollTop
。
-
offsetLeft
/offsetTop
是元素本身相對於母元素的水平/垂直距離。 -
clientLeft
/clientTop
是元素本身內外的水平/垂直距離,也就是左邊/上面的邊界寬度。(但要注意文字右到左時,左邊有捲軸的情況下,也會包含捲軸寬度) -
scrollLeft
/scrollTop
是「內容」被捲動的距離,也就是內容頂端和捲軸頂端的相對距離。這個屬性很常用到,一定要跟他很熟!
document.documentElement
如果我們想要取得整個文件的寬度/高度,該怎麼做呢?我們可以用 document.documentElement
這個特殊的DOM node,他對應到 <html>
這個 tag。
上述原則同樣適用於 document.documentElement
,但是相較一般的DOM node,額外多了一些tricky之處,需要特別注意。
clientWidth
/clientHeight
是文件「不包括捲軸」的寬度/高度;document.documentElement
還有另一組特殊的屬性innerWidth
/innerHeight
,是文件「包括捲軸」的寬度/高度。- 文件的完整寬度/高度(包含捲軸之外部分),考慮到瀏覽器相容性的問題,不能用
scrollWidth
/scrollHeight
,而要用
let scrollHeight = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
);
- 目前捲軸的捲動高度,理論上可以用
scrollWidth
/scrollTop
,但是因為瀏覽器相容性的問題,還是改用相容性更佳的window.pageXOffset
/pageYOffset
比較保險。
getComputedStyle()
還有另一種方法可以取得元素的寬高資訊,那就是用getComputedStyle()
這個 API 取得元素的CSS,然後我們就可以用 getComputedStyle(elem).width
取得寬度。
但實務上並不推薦這麼做,有幾個原因:
width
會隨著box-sizing
這個屬性的改變而有不同的計算方式。舉例而言,同樣是width: 300px; padding: 12px;
,當box-sizing: content-box;
時,實際寬度除了內容本身的 300px ,還會外加 padding 12 * 2,一共 324px,而box-sizing: border-box;
的時候,實際寬度就會只有 300px。- 同上,300px也可能會包含了捲軸的寬度,但可能我們想要的是不包含捲軸的寬度 (應用
clientWidth
)。 - 值可能會是
12px
或是auto
這類的字串
常見應用
無限捲動 (Infinite Scroll)
前端經常實作的其中一個功能就是無限捲動,當捲軸捲到接近底部的時候,向server端要更多資料。
所以我們必須知道「內容底端距離捲軸底端的距離」。雖然我們已經知道「內容頂端與捲軸頂端的距離」是 elem.scrollTop
,但很遺憾的是並沒有elem.scrollBottom
這個屬性,
幸好我們可以很容易地算出來「內容底端距離捲軸底端的距離」= elem.scrollHeight - elem.scrollTop - elem.clientHeight
,因為完整內容高度 (scrollHeight
) = 內容頂端與捲軸頂端的距離 (scrollTop
) + 捲軸本身高度 (clientHeight
) + 內容底端與捲軸底端的距離。
如何計算捲軸的寬度?
我們會需要利用容器和內容的寬度去計算。捲軸的寬度=內容的完整寬度 (child.offsetWidth
) 減去內容實際的寬度 (parent.clientWidth
)
Cheetsheet
截圖自:Element size and scrolling - javascript.info。