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