摘要:行內(nèi)級元素生成行內(nèi)級盒,而這些盒會參與行內(nèi)格式化上下文。行盒在行內(nèi)格式化上下文中,盒從包含塊的頂部一個接一個地水平擺放。我們進(jìn)入下一個話題,行盒高度計(jì)算。整個行盒的高度即盒上邊緣到盒下邊緣。
前言碎碎語:標(biāo)題問題在昨天困擾了筆者很久很久,早上把問題提到了各網(wǎng)絡(luò)也暫時沒有回復(fù)。因?yàn)槊魈煲缙痫w異地參加一場校招面試,筆者還是很緊張的,但奈何問題不解決寢食難安……所以還是卯起勁重新思考這個問題,算是暫時有了一個自己比較認(rèn)可以及清晰的答案,與各位讀者分享。如您有不同觀點(diǎn)想法意見建議,懇請斧正!
正式探討之前,我們觀察一個現(xiàn)象(在 Chrome 下的表現(xiàn),其他瀏覽器下的表現(xiàn)和計(jì)算可能有細(xì)微差別):
上圖對應(yīng)的 HTML 是(之后的探討均基于此):
Line Height Some Text
我們來計(jì)算下 DIV 和 SPAN 的高度
document.getElementsByTagName("div")[0].offsetHeight //93 document.getElementsByTagName("span")[0].offsetHeight //42
對于此圖,筆者產(chǎn)生如下疑問:
line-height 為 32px,為何 SPAN 的高度為 42px?
DIV 的高度 93px,比 IMG 高度加外邊距 90px 以及 SPAN 高度 42px 都要大,如何計(jì)算的?
圖片和文本下的空白(即便沒有文本一樣存在)是如何產(chǎn)生的?
假設(shè)我們把 IMG 刪除,HTML 部分改為:
Some Text
此時來計(jì)算:
document.getElementsByTagName("div")[0].offsetHeight //32 document.getElementsByTagName("span")[0].offsetHeight //42
新問題又來了:
DIV 的子元素高度為 42px,為何沒有“撐起” DIV 的高度?
以上問題就是本文要探討的了。覆蓋了五個知識點(diǎn):
行內(nèi)盒(或行內(nèi)不可替換元素)的高度
行內(nèi)可替換元素的高度
行盒的高度
行距與行高
建立行內(nèi)格式化上下文的塊盒的 auto 高度
所以在探討之前,筆者已假設(shè)您知道這些概念:行內(nèi)盒、行內(nèi)不可替換元素、行內(nèi)可替換元素、行盒、行內(nèi)格式化上下文。如果您還有點(diǎn)不清楚,我們可以快速補(bǔ)習(xí)下:
可替換元素、不可替換元素
簡單地講,可替換元素是指須根據(jù)其標(biāo)簽和屬性來決定具體顯示內(nèi)容的元素,如本文中會探討的 IMG 元素,其具體顯示內(nèi)容由 src 等屬性決定; 不可替換元素則是內(nèi)容直接呈現(xiàn)的元素。如本文會探討的 DIV 和 SPAN 等。
塊盒
此概念是塊格式化上下文的內(nèi)容,要解釋起來就更復(fù)雜啦,筆者粗陋地給您一個描述:塊盒通常是 display: block 的不可替換元素。
行內(nèi)級元素、行內(nèi)級盒、行內(nèi)盒、行內(nèi)格式化上下文
display: inline|inline-table|inline-block 產(chǎn)生行內(nèi)級元素。行內(nèi)級元素生成行內(nèi)級盒,而這些盒會參與行內(nèi)格式化上下文。
display 值是 inline 的不可替換元素會生成一個行內(nèi)盒。
不是行內(nèi)盒的行內(nèi)級盒被稱為原子行內(nèi)級盒。
行盒
在行內(nèi)格式化上下文中,盒從包含塊的頂部一個接一個地水平擺放。包含了一行里所有盒的矩形區(qū)域被稱為行盒。一個段落就是多個行盒的垂直堆疊。
因此,我們可以得到下圖(大致描摹):
現(xiàn)在開始計(jì)算!
1 行內(nèi)可替換元素和文檔流內(nèi)行內(nèi)塊可替換元素高度計(jì)算W3C 有明確規(guī)范,如下:
如果 height 和 width 計(jì)算值均為 auto 且該元素有固有高度,那么該固有高度為 height 使用值。
否則,如果 height 計(jì)算值為 auto,且該元素有一個固有比例,則 height 的使用值為:
width 使用值 / 固有比例
否則,如果 height 計(jì)算值為 auto,且該元素有固有高度,那么該固有高度為 height 使用值。
否則,如果 height 計(jì)算值為 auto,但以上情況均不符合,那么 height 的使用值必須設(shè)定為一個最大矩形的高度,該矩形比例為2:1,高度不超過150px,且寬度不大于設(shè)備寬度。
因此,在我們的實(shí)例中,IMG 盒的高度為 80+10 = 90px。
2 行內(nèi)盒的高度計(jì)算“高度”一詞在這里頗有歧義,筆者認(rèn)為,總共可以有三種概念需要辨析:
行內(nèi)盒的內(nèi)容區(qū)域高度
行內(nèi)盒的盒高度
計(jì)算行盒高度時的行內(nèi)盒的盒高度
您可能對第二和第三解釋抱有疑問,但我們先擱置懷疑,把清楚明白的東西先解決。
當(dāng)我們用 JavaScript 去獲取一個行內(nèi)盒的 offsetHeight 值時,如我們上面所做的:
document.getElementsByTagName("span")[0].offsetHeight
筆者將此高度稱作“行內(nèi)盒的盒高度”,類比于我們所熟知的塊盒盒高度。其計(jì)算值是:
內(nèi)容區(qū)域高度 + 上下邊框 + 上下內(nèi)邊距 = 行內(nèi)盒的盒高度
邊框和內(nèi)邊距的寬度默認(rèn)為 0,否則為我們自己指定,但“內(nèi)容區(qū)域高度”是怎么計(jì)算的呢?
W3C 這么說:
height 不適用。內(nèi)容區(qū)域的高度應(yīng)基于字體,但本規(guī)范沒有指定如何。用戶代理可能,比如說,使用行高盒 EM-Box 或字體的最大上端部 Ascender 和下端部 Descender。(后一種會確保有部分在行高盒之上或之下的字符仍然落在內(nèi)容區(qū)域內(nèi),但會導(dǎo)致不同字體有大小不一的盒子;前者則確保作者可以控制相對于 line-height 的背景設(shè)計(jì),但也導(dǎo)致字符繪制在其內(nèi)容區(qū)域之外。)
言下之意:
height 屬性無效
行內(nèi)盒內(nèi)容區(qū)域高度在規(guī)范里面沒有定義,瀏覽器可以自己折騰
既然規(guī)范沒有明確規(guī)定計(jì)算,我們讓瀏覽器實(shí)測一下。筆者瀏覽器測試如下:
Chrome 42
IE11 42
Firefox 43
如果我們更改字體,假設(shè)應(yīng)用如下 CSS
body { font-family: Simsun; }
Chrome 33
IE11 37
Firefox 35
而如果我們修改 line-height,以上結(jié)果均不受影響。
筆者也曾疑惑,這個 offsetHeight 就是內(nèi)容區(qū)域高度嗎?答案:是。筆者的驗(yàn)證方法是基于 W3C 如下規(guī)定:
盡管不可替換元素的外邊距、邊框以及內(nèi)邊距不納入行盒的計(jì)算,它們?nèi)匀讳秩驹谛袃?nèi)盒的周圍。這意味著如果 line-height 指定的高度小于被包含盒的內(nèi)容高度,內(nèi)邊距和邊框的背景和顏色可能“流進(jìn)”毗鄰的行盒。用戶代理應(yīng)當(dāng)按文檔順序渲染這些盒。這會造成后面的盒的邊框繪制在前面盒的邊框和文本上。
您可以用以下代碼實(shí)測,會發(fā)現(xiàn)紅色行內(nèi)盒的背景溢出到了黑色行內(nèi)盒所在的行盒。
Some Text
Some Text
可知內(nèi)容區(qū)域高度,即行內(nèi)盒沒有內(nèi)邊距和邊框時的 offsetHeight。
因此總結(jié)論是:
行內(nèi)盒的內(nèi)容區(qū)域高度計(jì)算沒有統(tǒng)一的標(biāo)準(zhǔn),不同的字體或者不同的瀏覽器都可能導(dǎo)致不同的結(jié)果,且其高度與 line-height 無關(guān)。
由此我們無法確切地獲得一個跨瀏覽器的行內(nèi)盒的內(nèi)容區(qū)域高度。同樣我們也無法確切獲得一個跨瀏覽器的行內(nèi)盒高度(因?yàn)槠溆?jì)算式里面就包括了不定變量內(nèi)容區(qū)域高度)。
但問題來了,不同瀏覽器都采用不同的行內(nèi)盒內(nèi)容區(qū)域高度,又如何能統(tǒng)一計(jì)算行盒以及塊容器的高度呢?這個問題便導(dǎo)致了筆者在上面所提到的“計(jì)算行盒高度時的行內(nèi)盒的盒高度”概念。
我們進(jìn)入下一個話題,行盒高度計(jì)算。
3 行盒高度計(jì)算根據(jù)規(guī)范,行盒的高度決定如下:
計(jì)算行盒內(nèi)每個行內(nèi)級盒的高度。對于可替換元素、行內(nèi)塊元素以及行內(nèi)表格元素,高度是其外邊距盒的高度;對于行內(nèi)盒,高度是其 line-height。
行內(nèi)級盒根據(jù)其 vertical-align 屬性垂直對齊。如果它們對齊 top 或 bottom,它們必須以能最小化行盒高度的方式對齊。如果這些盒足夠高,則有多種解決方案并且 CSS2.1 沒有規(guī)定此行盒的基線的位置。
行盒高度是最上盒頂部到最下盒底部的距離。
懂了:W3C 盡管允許瀏覽器有自己的行內(nèi)盒內(nèi)容區(qū)域計(jì)算方式,但統(tǒng)一了一個行盒高度的計(jì)算方式:
計(jì)算行盒的高度時,針對行內(nèi)盒,高度直接取 line-height。行內(nèi)盒可以有邊框、內(nèi)邊距、外邊距,然而跟行盒的高度完全沒關(guān)系!
根據(jù)此規(guī)定,我們很快可以得出,計(jì)算行盒高度時,SPAN 盒的高度取 32px。
接著,由于我們的 vertical-align 是默認(rèn)的 baseline,因此,應(yīng)當(dāng)把盒的基線同父盒的基線對齊。如果盒沒有基線,對齊盒的下外邊距邊緣與父盒的基線。也就是說,把 SPAN 盒的基線同 DIV 盒的基線對齊,把 IMG 盒的下外邊距邊緣同 DIV 盒的基線對齊。
下圖是字體的基線、上下端線等位置信息
圖片來源:http://blog.justfont.com/
筆者作圖如下:
假設(shè)我們設(shè) DIV 盒的基線是 0,則 IMG 盒的下邊緣同 DIV 盒基線對齊;上邊緣(上外邊距邊緣頂部)在高于基線 90px 處。而 SPAN 盒由于其基線對齊 DIV 盒基線,故其行盒下邊緣略低于基線。
整個行盒的高度即 IMG 盒上邊緣到 SPAN 盒下邊緣。假設(shè)沒有 IMG 元素,則高度為 SPAN 盒的 line-height。
但讀者您可能注意到了,29 和 -3 是怎么得來的呢?下面,筆者帶您算!
4 行距和行高計(jì)算29 和 -3 兩值是在計(jì)算行距和行高后得來的。我們先來看規(guī)范:
CSS 假設(shè)每種字體都由字體特性來指定一個基線之上的特性高度和之下的特性深度。本節(jié)中我們用A表示(給定字體給定字號的)高度,用D表示深度。同時定義 AD = A + D,即從頂部到底部的距離。(參見下面如何找到TrueType和OpenType字體的A和D)注意該字體的這些特性是就整個而言的,無須對應(yīng)任何個別字符的上端部和下端部。
用戶代理必須在一個不可替換行內(nèi)盒中依照字符的相應(yīng)基線對齊各個字符。接著,就每個字符來決定A和D。注意單個元素的字符可能來自于不同字體因此不見得所有的A和D一樣。如果行內(nèi)盒完全不包含字符,則被視為包含了一個具有元素首個可用字體的A和D的支柱(一個零寬度的不可見字符)。
接著對每個字符添加行距L,其中 L = line-height - AD。行距的一般添加到A之上,另一半添加到D之下,從而賦予字符以及其行距一個基線之上的完整高度 A" = A + L/2,以及完整深度 D" = D+ L/2。
注意。L可能為負(fù)。
包含了所有字符以及字符兩側(cè)半行距的行內(nèi)盒的高度正是 line-height。
我們在上述規(guī)定中接觸到了這些概念:特性高度 A,特性深度 D,頂部到底部距離 AD,完整高度 A",完整深度 D",行距 L。
關(guān)于特性值,筆者 Google 到一個網(wǎng)站,推薦讀者使用:
http://fontsgeek.com/
不得不吐槽下,國內(nèi)真的很難找到這樣專業(yè)精致的字體網(wǎng)站(也可能是我的打開方式不對 >_<)。
好,我們可以獲得我們實(shí)例中 Microsoft YaHei 的字體特性了:Dcsender -536;Height 2703。
AD 即內(nèi)容區(qū)域高度,在本例中是 42
D 即字體下端(基線之下)高度,為 42*(536/2703) = 8
L = 32 - 42 = -10
故,D" = 8 + -10/2 = 3
即知行內(nèi)盒的下邊緣在基線之下 3px。同時行內(nèi)盒的高度被視為 32px,故亦知其上邊緣在基線之上 29px 處。
我們說啦,整個行盒的高度即 IMG 盒上邊緣到 SPAN 盒下邊緣。所以得行內(nèi)盒高度為 90 + 3 = 93px。
5 建立行內(nèi)格式化上下文的塊盒的 auto 高度根據(jù) W3C CSS2.1:10.6.3,該高度是從其上內(nèi)容邊緣到其最后一個行盒的下邊緣。只考慮文檔流內(nèi)子盒,絕對定位和浮動子盒應(yīng)被忽略,相對定位子盒不考慮位移,子盒可以是匿名盒。
在本例中,DIV 盒的行內(nèi)格式化上下文僅有一個行盒,故其高度取該行盒高度,93px。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/111177.html
摘要:盒的類型會影響其在視覺格式化模型中的表現(xiàn)。浮動元素絕對定位元素根元素都被稱為脫離文檔流其他元素被稱為文檔流內(nèi)。 視覺格式化模型 Visual Formatting Model URL:http://www.w3.org/TR/CSS2/visuren.html Translator: HaoyCn Date: 14th of Aug, 2015 本文并未全部翻譯,譯者在原文基礎(chǔ)上...
摘要:行盒的寬度由其包含塊給予,但可能因浮動而縮小。絕對定位不可替換元素的使用值約束為包含塊寬度如果和均為首先將以及值為的設(shè)為。 2015/10/08: 原10.8標(biāo)題 行盒高度計(jì)算改為10.8 行高計(jì)算。英文原文為line height。由于翻譯時候看到那段結(jié)論是行盒的高度,腦抽就把原本翻譯對的標(biāo)題改了下,剛回顧一番深覺不妥,故改回來。 原文:http://www.w3.org/TR/CS...
摘要:當(dāng)兩個及以上外邊距折疊,合并后的外邊距寬度是發(fā)生折疊的外邊距中的最大寬度。如果該元素的外邊距同其父元素的上外邊距折疊,則該盒的上邊框邊緣同其父元盒的上邊框邊緣相同。 2017-07-20: 關(guān)于外邊距折疊, 推薦問題: https://segmentfault.com/q/10... 8 盒模型 Box Model URL: http://www.w3.org/TR/CSS2/box...
摘要:中各種布局的背后,實(shí)質(zhì)上是各種的組合。相反,一些塊容器盒,比如非替換行內(nèi)塊及非替換表格單元格,不是塊級盒。描述元素跟它的后代之間的影響。行盒行盒由行內(nèi)格式化上下文產(chǎn)生的盒,用于表示一行。彈性容器外和彈性項(xiàng)目內(nèi)的一切元素都不受影響。 CSS中各種布局的背后,實(shí)質(zhì)上是各種*FC的組合。CSS2.1 中只有 BFC 和 IFC, CSS3 中還增加了 FFC 和 GFC。 盒模型(Box M...
摘要:而圣杯布局跟雙飛翼布局就是能夠不考慮主體的位置,能夠只通過代碼就改變相應(yīng)的布局,這也是優(yōu)點(diǎn)之一。如果在圣杯布局的基礎(chǔ)上,給它一個多余的標(biāo)簽,把包起來,這就是雙飛翼布局。這里有個嘗試頁面,利用雙飛翼,實(shí)現(xiàn)了一套柵格化布局系統(tǒng)。 塊級格式上下文(Block formatting context) 普通流(Normal Flow) 在普通流中,元素按照其在 HTML 中的先后位置至上而...
閱讀 2136·2023-04-26 00:23
閱讀 807·2021-09-08 09:45
閱讀 2435·2019-08-28 18:20
閱讀 2541·2019-08-26 13:51
閱讀 1594·2019-08-26 10:32
閱讀 1391·2019-08-26 10:24
閱讀 2026·2019-08-26 10:23
閱讀 2195·2019-08-23 18:10