W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
JavaScript 中有許多屬性可讓我們讀取有關(guān)元素寬度、高度和其他幾何特征的信息。
我們?cè)?JavaScript 中移動(dòng)或定位元素時(shí),我們會(huì)經(jīng)常需要它們。
作為演示屬性的示例元素,我們將使用下面給出的元素:
<div id="example">
...Text...
</div>
<style>
#example {
width: 300px;
height: 200px;
border: 25px solid #E8C48F;
padding: 20px;
overflow: auto;
}
</style>
它有邊框(border),內(nèi)邊距(padding)和滾動(dòng)(scrolling)等全套功能。但沒有外邊距(margin),因?yàn)樗鼈儾皇窃乇旧淼囊徊糠郑⑶宜鼈儧]什么特殊的屬性。
這個(gè)元素看起來就像這樣:
注意滾動(dòng)條
上圖演示了元素具有滾動(dòng)條這種最復(fù)雜的情況。一些瀏覽器(并非全部)通過從內(nèi)容(上面標(biāo)記為 “content width”)中獲取空間來為滾動(dòng)條保留空間。
因此,如果沒有滾動(dòng)條,內(nèi)容寬度將是
300 px
,但是如果滾動(dòng)條寬度是16px
(不同的設(shè)備和瀏覽器,滾動(dòng)條的寬度可能有所不同),那么還剩下300 - 16 = 284px
,我們應(yīng)該考慮到這一點(diǎn)。這就是為什么本章的例子總是假設(shè)有滾動(dòng)條。如果沒有滾動(dòng)條,一些計(jì)算會(huì)更簡(jiǎn)單。
文本可能會(huì)溢出到 ?
padding-bottom
? 中在我們的插圖中的 padding 中通常顯示為空,但是如果元素中有很多文本,并且溢出了,那么瀏覽器會(huì)在
padding-bottom
處顯示“溢出”文本,這是正?,F(xiàn)象。
這是帶有幾何屬性的整體圖片:
這些屬性的值在技術(shù)上講是數(shù)字,但這些數(shù)字其實(shí)是“像素(pixel)”,因此它們是像素測(cè)量值。
讓我們從元素外部開始探索屬性。
這些屬性很少使用,但它們?nèi)匀皇恰白钔饷妗钡膸缀螌傩?,所以我們將從它們開始。
offsetParent
是最接近的祖先(ancestor),在瀏覽器渲染期間,它被用于計(jì)算坐標(biāo)。
最近的祖先為下列之一:
position
? 為 ?absolute
?、?relative
?、fixed 或 ?sticky
?),<td>
?,?<th>
?,?<table>
?,<body>
?。屬性 offsetLeft/offsetTop
提供相對(duì)于 offsetParent
左上角的 x/y 坐標(biāo)。
在下面這個(gè)例子中,內(nèi)部的 <div>
有 <main>
作為 offsetParent
,并且 offsetLeft/offsetTop
讓它從左上角位移(180
):
<main style="position: relative" id="main">
<article>
<div id="example" style="position: absolute; left: 180px; top: 180px">...</div>
</article>
</main>
<script>
alert(example.offsetParent.id); // main
alert(example.offsetLeft); // 180(注意:這是一個(gè)數(shù)字,不是字符串 "180px")
alert(example.offsetTop); // 180
</script>
有以下幾種情況下,offsetParent
的值為 null
:
display:none
? 或者不在文檔中)。<body>
? 與 ?<html>
?。position:fixed
? 的元素。現(xiàn)在,讓我們繼續(xù)關(guān)注元素本身。
這兩個(gè)屬性是最簡(jiǎn)單的。它們提供了元素的“外部” width/height?;蛘?,換句話說,它的完整大?。òㄟ吙颍?/p>
對(duì)于我們的示例元素:
offsetWidth = 390
? —— 外部寬度(width),可以計(jì)算為內(nèi)部 CSS-width(?300px
?)加上 padding(?2 * 20px
?)和 border(?2 * 25px
?)。offsetHeight = 290
? —— 外部高度(height)。對(duì)于未顯示的元素,幾何屬性為 0/null
僅針對(duì)顯示的元素計(jì)算幾何屬性。
如果一個(gè)元素(或其任何祖先)具有
display:none
或不在文檔中,則所有幾何屬性均為零(或offsetParent
為null
)。
例如,當(dāng)我們創(chuàng)建了一個(gè)元素,但尚未將其插入文檔中,或者它(或它的祖先)具有
display:none
時(shí),offsetParent
為null
,并且offsetWidth
和offsetHeight
為0
。
我們可以用它來檢查一個(gè)元素是否被隱藏,像這樣:
function isHidden(elem) { return !elem.offsetWidth && !elem.offsetHeight; }
請(qǐng)注意,對(duì)于會(huì)展示在屏幕上,但大小為零的元素,它們的
isHidden
返回true
。
在元素內(nèi)部,我們有邊框(border)。
為了測(cè)量它們,可以使用 clientTop
和 clientLeft
。
在我們的例子中:
clientLeft = 25
? —— 左邊框?qū)挾?/li>
clientTop = 25
? —— 上邊框?qū)挾?/li>
……但準(zhǔn)確地說 —— 這些屬性不是邊框的 width/height,而是內(nèi)側(cè)與外側(cè)的相對(duì)坐標(biāo)。
有什么區(qū)別?
當(dāng)文檔從右到左顯示(操作系統(tǒng)為阿拉伯語(yǔ)或希伯來語(yǔ))時(shí),影響就顯現(xiàn)出來了。此時(shí)滾動(dòng)條不在右邊,而是在左邊,此時(shí) clientLeft
則包含了滾動(dòng)條的寬度。
在這種情況下,clientLeft
的值將不是 25
,而是加上滾動(dòng)條的寬度 25 + 16 = 41
。
這是希伯來語(yǔ)的例子:
這些屬性提供了元素邊框內(nèi)區(qū)域的大小。
它們包括了 “content width” 和 “padding”,但不包括滾動(dòng)條寬度(scrollbar):
在上圖中,我們首先考慮 clientHeight
。
這里沒有水平滾動(dòng)條,所以它恰好是 border 內(nèi)的總和:CSS-height 200px
加上頂部和底部的 padding(2 * 20px
),總計(jì) 240px
。
現(xiàn)在 clientWidth
—— 這里的 “content width” 不是 300px
,而是 284px
,因?yàn)楸粷L動(dòng)條占用了 16px
。所以加起來就是 284px
加上左側(cè)和右側(cè)的 padding,總計(jì) 324px
。
如果這里沒有 padding,那么 clientWidth/Height
代表的就是內(nèi)容區(qū)域,即 border 和 scrollbar(如果有)內(nèi)的區(qū)域。
因此,當(dāng)沒有 padding 時(shí),我們可以使用 clientWidth/clientHeight
來獲取內(nèi)容區(qū)域的大小。
這些屬性就像 clientWidth/clientHeight
,但它們還包括滾動(dòng)出(隱藏)的部分:
在上圖中:
scrollHeight = 723
? —— 是內(nèi)容區(qū)域的完整內(nèi)部高度,包括滾動(dòng)出的部分。scrollWidth = 324
? —— 是完整的內(nèi)部寬度,這里我們沒有水平滾動(dòng),因此它等于 ?clientWidth
?。我們可以使用這些屬性將元素展開(expand)到整個(gè) width/height。
像這樣:
// 將元素展開(expand)到完整的內(nèi)容高度
element.style.height = `${element.scrollHeight}px`;
屬性 scrollLeft/scrollTop
是元素的隱藏、滾動(dòng)部分的 width/height。
在下圖中,我們可以看到帶有垂直滾動(dòng)塊的 scrollHeight
和 scrollTop
。
換句話說,scrollTop
就是“已經(jīng)滾動(dòng)了多少”。
?
scrollLeft/scrollTop
? 是可修改的大多數(shù)幾何屬性是只讀的,但是
scrollLeft/scrollTop
是可修改的,并且瀏覽器會(huì)滾動(dòng)該元素。
如果你點(diǎn)擊下面的元素,則會(huì)執(zhí)行代碼
elem.scrollTop += 10
。這使得元素內(nèi)容向下滾動(dòng)10px
。
![]()
將
scrollTop
設(shè)置為0
或一個(gè)大的值,例如1e9
,將會(huì)使元素滾動(dòng)到頂部/底部。
我們剛剛介紹了 DOM 元素的幾何屬性,它們可用于獲得寬度、高度和計(jì)算距離。
但是,正如我們?cè)?nbsp;樣式和類 一章所知道的那樣,我們可以使用 getComputedStyle
來讀取 CSS-width 和 height。
那為什么不像這樣用 getComputedStyle
讀取元素的 width 呢?
let elem = document.body;
alert( getComputedStyle(elem).width ); // 顯示 elem 的 CSS width
為什么我們應(yīng)該使用幾何屬性呢?這里有兩個(gè)原因:
width/height
? 取決于另一個(gè)屬性:?box-sizing
?,它定義了“什么是” CSS 寬度和高度。出于 CSS 的目的而對(duì) ?box-sizing
? 進(jìn)行的更改可能會(huì)破壞此類 JavaScript 操作。width/height
? 可能是 ?auto
?,例如內(nèi)聯(lián)(inline)元素:<span id="elem">Hello!</span>
<script>
alert( getComputedStyle(elem).width ); // auto
</script>
從 CSS 的觀點(diǎn)來看,width:auto
是完全正常的,但在 JavaScript 中,我們需要一個(gè)確切的 px
大小,以便我們?cè)谟?jì)算中使用它。因此,這里的 CSS 寬度沒什么用。
還有另一個(gè)原因:滾動(dòng)條。有時(shí),在沒有滾動(dòng)條的情況下代碼工作正常,當(dāng)出現(xiàn)滾動(dòng)條時(shí),代碼就出現(xiàn)了 bug,因?yàn)樵谀承g覽器中,滾動(dòng)條會(huì)占用內(nèi)容的空間。因此,可用于內(nèi)容的實(shí)際寬度小于 CSS 寬度。而 clientWidth/clientHeight
則會(huì)考慮到這一點(diǎn)。
……但是,使用 getComputedStyle(elem).width
時(shí),情況就不同了。某些瀏覽器(例如 Chrome)返回的是實(shí)際內(nèi)部寬度減去滾動(dòng)條寬度,而某些瀏覽器(例如 Firefox)返回的是 CSS 寬度(忽略了滾動(dòng)條)。這種跨瀏覽器的差異是不使用 getComputedStyle
而依靠幾何屬性的原因。
如果你的瀏覽器保留了滾動(dòng)條的空間(大多數(shù) Windows 中的瀏覽器),那么你可以在下面測(cè)試它。
https://zh.js.cx/article/size-and-scroll/cssWidthScroll/
帶有文本的元素具有 width:300px
。
在桌面 Windows 操作系統(tǒng)上,F(xiàn)irefox、Chrome、Edge 都為滾動(dòng)條保留了空間。但 Firefox 顯示的是 300px
,而 Chrome 和 Edge 顯示較少。這是因?yàn)?Firefox 返回 CSS 寬度,其他瀏覽器返回“真實(shí)”寬度。
請(qǐng)注意,所描述的差異只是關(guān)于從 JavaScript 讀取的 getComputedStyle(...).width
,而視覺上看,一切都是正確的。
元素具有以下幾何屬性:
offsetParent
? —— 是最接近的 CSS 定位的祖先,或者是 ?td
?,?th
?,?table
?,?body
?。offsetLeft/offsetTop
? —— 是相對(duì)于 ?offsetParent
? 的左上角邊緣的坐標(biāo)。offsetWidth/offsetHeight
? —— 元素的“外部” width/height,邊框(border)尺寸計(jì)算在內(nèi)。clientLeft/clientTop
? —— 從元素左上角外角到左上角內(nèi)角的距離。對(duì)于從左到右顯示內(nèi)容的操作系統(tǒng)來說,它們始終是左側(cè)/頂部 border 的寬度。而對(duì)于從右到左顯示內(nèi)容的操作系統(tǒng)來說,垂直滾動(dòng)條在左邊,所以 ?clientLeft
? 也包括滾動(dòng)條的寬度。clientWidth/clientHeight
? —— 內(nèi)容的 width/height,包括 padding,但不包括滾動(dòng)條(scrollbar)。scrollWidth/scrollHeight
? —— 內(nèi)容的 width/height,就像 ?clientWidth/clientHeight
? 一樣,但還包括元素的滾動(dòng)出的不可見的部分。scrollLeft/scrollTop
? —— 從元素的左上角開始,滾動(dòng)出元素的上半部分的 width/height。除了 scrollLeft/scrollTop
外,所有屬性都是只讀的。如果我們修改 scrollLeft/scrollTop
,瀏覽器會(huì)滾動(dòng)對(duì)應(yīng)的元素。
elem.scrollTop
屬性是從頂部滾動(dòng)出來的部分的大小。如何獲得底部滾動(dòng)的大?。ㄎ覀兎Q其為 scrollBottom
)?
編寫適用于任意 elem
的代碼。
P.S. 請(qǐng)檢查你的代碼:如果沒有滾動(dòng),或元素底部已經(jīng)完全滾動(dòng)完成,那么它應(yīng)該返回 0
。
解決方案:
let scrollBottom = elem.scrollHeight - elem.scrollTop - elem.clientHeight;
換句話說:(完全高度)減去(已滾出頂部的高度)減去(可見部分的高度)—— 得到的結(jié)果就是滾動(dòng)出來的底部的部分。
編寫代碼,返回標(biāo)準(zhǔn)滾動(dòng)條寬度。
對(duì)于 Windows,它通常在 12px
和 20px
之間變化。如果瀏覽器沒有為其保留任何空間(滾動(dòng)條以半透明的形式處于文本上面,也是可能發(fā)生的),那么它可能是 0px
。
P.S. 該代碼應(yīng)適用于任何 HTML 文檔,而不依賴于其內(nèi)容。
為了獲得滾動(dòng)條的寬度,我們可以創(chuàng)建一個(gè)帶有滾動(dòng)條的元素,但是沒有邊框(border)和內(nèi)邊距(padding)。
然后,它的全寬度 offsetWidth
和內(nèi)部?jī)?nèi)容寬度 clientWidth
之間的差值就是滾動(dòng)條的寬度:
// 創(chuàng)建一個(gè)包含滾動(dòng)條的 div
let div = document.createElement('div');
div.style.overflowY = 'scroll';
div.style.width = '50px';
div.style.height = '50px';
// 必須將其放入文檔(document)中,否則其大小將為 0
document.body.append(div);
let scrollWidth = div.offsetWidth - div.clientWidth;
div.remove();
alert(scrollWidth);
源文件的效果如下:
區(qū)域(field)的中心坐標(biāo)是多少?
計(jì)算它們,并將小球置于綠色的區(qū)域(field)中心:
10
?、?20
?、?30
? 像素)以及任意大小的區(qū)域(field),而不應(yīng)該綁定到給定值。P.S. 當(dāng)然了,置于中心的操作通過 CSS 也可以完成,但是這里我們需要通過 JavaScript 完成。此外,當(dāng)必須使用 JavaScript 時(shí),我們可能會(huì)遇到其他話題以及更加復(fù)雜的情況,這里我們只是做一個(gè)“熱身”。
球具有 position:absolute
。這意味著它的 left/top
坐標(biāo)是從最近的具有定位屬性的元素開始測(cè)量的,這個(gè)元素即 #field
(因?yàn)樗?nbsp;position:relative
)。
坐標(biāo)從場(chǎng)(field)的左上角內(nèi)側(cè)開始:
內(nèi)部的場(chǎng)(field)的 width/height 是 clientWidth/clientHeight
。所以場(chǎng)(field)的中心坐標(biāo)為 (clientWidth/2, clientHeight/2)
。
……但是,如果我們將 ball.style.left/top
設(shè)置為這種值,那么在中心的會(huì)是球的左上邊緣,而不是整個(gè)球:
ball.style.left = Math.round(field.clientWidth / 2) + 'px';
ball.style.top = Math.round(field.clientHeight / 2) + 'px';
這是它將顯示出來的效果:
為了使球的中心與場(chǎng)(field)的中心重合,我們應(yīng)該把球向左移動(dòng)球?qū)挾鹊囊话?,并向上移?dòng)球高度的一半:
ball.style.left = Math.round(field.clientWidth / 2 - ball.offsetWidth / 2) + 'px';
ball.style.top = Math.round(field.clientHeight / 2 - ball.offsetHeight / 2) + 'px';
現(xiàn)在,球終于居中了。
注意:陷阱!
當(dāng)
<img>
沒有 width/height 時(shí),代碼將無法可靠地工作:
<img src="ball.png" id="ball">
當(dāng)瀏覽器不知道圖片的 width/height(通過標(biāo)簽 attribute 或 CSS)時(shí),它會(huì)假定它們等于 0
,直到圖片加載完成。
因此,在圖片加載完成之前,ball.offsetWidth
的值為 0
。這會(huì)導(dǎo)致上面的代碼中會(huì)有錯(cuò)誤的坐標(biāo)。
在第一次加載完成后,瀏覽器通常會(huì)緩存該圖片,并在下一次加載時(shí),瀏覽器會(huì)立即擁有該圖片的大小。但是在第一次加載時(shí),ball.offsetWidth
的值為 0
。
我們應(yīng)該通過在 <img>
中添加 width/height
來解決這個(gè)問題:
<img src="ball.png" width="40" height="40" id="ball">
……或者在 CSS 中提供大小:
#ball {
width: 40px;
height: 40px;
}
getComputedStyle(elem).width
與 elem.clientWidth
之間有什么不同點(diǎn)?
指出至少三種不同點(diǎn)。當(dāng)然越多越好。
不同點(diǎn):
clientWidth
? 值是數(shù)值,而 ?getComputedStyle(elem).width
? 返回一個(gè)以 ?px
? 作為后綴的字符串。getComputedStyle
? 可能會(huì)返回非數(shù)值的 width,例如內(nèi)聯(lián)(inline)元素的 ?"auto"
?。clientWidth
? 是元素的內(nèi)部?jī)?nèi)容區(qū)域加上 padding,而 CSS width(具有標(biāo)準(zhǔn)的 ?box-sizing
?)是內(nèi)部?jī)?nèi)容區(qū)域,不包括 padding。clientWidth
? 屬性總是相同的:如果為滾動(dòng)條保留了空間,那么將減去滾動(dòng)條的大小。Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: