在聊這個(gè)話題之前,我們可能得先簡(jiǎn)單說(shuō)說(shuō) 視覺(jué)格式化模型
這個(gè)概念。
視覺(jué)格式化模型
的全稱是 Visual formatting model
,它被用來(lái)描述用戶代理(比如瀏覽器)在圖形媒體下如何處理文檔樹(shù)。
在 視覺(jué)格式化模型
中,每個(gè)文檔樹(shù)的元素會(huì)根據(jù)框模型產(chǎn)生零到多個(gè)框(boxes)。這些框的布局取決于框的尺寸,類型,定位方式(正常流,浮動(dòng)和絕對(duì)定位),元素之間的關(guān)系和外部信息(例如:視口 ① 大小,置換元素的固有尺寸等等)。
舉個(gè)最簡(jiǎn)單的例子來(lái)講,假設(shè)一個(gè)頁(yè)面上有2個(gè)div,那么第2個(gè)div的位置會(huì)取決第1個(gè)div的高度定義;假設(shè)更復(fù)雜一點(diǎn),第1個(gè)div是浮動(dòng)的,那么第2個(gè)div的位置還要取決于第1個(gè)div的寬度。
在 CSS
中,可能會(huì)產(chǎn)生不同類型的框,框的類型取決于 display
屬性的設(shè)定。某種程度上,框的類型會(huì)影響其在視覺(jué)格式化模型中的表現(xiàn)。接下來(lái)會(huì)詳細(xì)的聊聊這些不同類型的框以及它們?cè)谝曈X(jué)可視化模型中的表現(xiàn)。
在說(shuō)這個(gè)之前,我們先回憶一下,大家常說(shuō)的一些名詞:
首先,來(lái)看看什么是 包含塊
?這個(gè)說(shuō)及 CSS
一般的都會(huì)提及的基本概念。
一個(gè)元素,它的框的尺寸和位置會(huì)相對(duì)于一個(gè)特定的矩形框邊緣來(lái)計(jì)算而得到,這個(gè)特定的矩形框稱之為該元素的 包含塊
。
(為)一個(gè)元素生成的框通常會(huì)充當(dāng)其子框的包含塊;當(dāng)我們叫一個(gè) 框的包含塊
時(shí),其實(shí)表達(dá)的是 該框所處的包含塊
,而不是其自身產(chǎn)生的包含塊。
每個(gè)框相對(duì)于其包含塊(該框所處的包含塊
)都會(huì)被給予一個(gè)位置,不過(guò)該框并不局限在包含塊內(nèi),有可能會(huì)溢出,通常這個(gè)時(shí)候你會(huì)借助 overflow
屬性來(lái)進(jìn)行處理。
除了說(shuō)什么是包含塊,這里順帶再介紹一下生成包含塊的一些特殊場(chǎng)景:
初始包含塊(initial containing block)
。position
值是 relative
或者 static
,其包含塊由最近的祖先 塊容器框
的內(nèi)容邊界(如果想知道什么是內(nèi)容邊界,可以先看看CSS盒模型)形成。舉個(gè)例子,
td
,th
就算有父容器tr
,但它們的包含塊卻是由 table 生成,因?yàn)?table
是 塊容器框 而tr
不是
position
值非 static
)祖先生成,如果不存在這樣的祖先,則采用初始包含塊;position: fixed
)的包含塊一般情況下都由視口 ① 生成;說(shuō)了這幾個(gè)特殊的情景,你會(huì)發(fā)現(xiàn)并不是所有的包含塊都是由父元素所生成。
塊級(jí)元素是那些視覺(jué)上會(huì)被格式化成塊狀的元素,通俗一點(diǎn)來(lái)說(shuō)就是那些會(huì)換新行的元素。display
屬性的:block
, list-item
, table
, flex
, grid
值都可以將一個(gè)元素設(shè)置成塊級(jí)元素。
舉個(gè)例子來(lái)說(shuō),
li
是一個(gè) 塊級(jí)元素,但也有人會(huì)說(shuō)它是一個(gè)塊元素
。嗯,li
確實(shí)是一個(gè)塊級(jí)元素,但并不是一個(gè)塊元素,為什么?
塊元素是 display
屬性值為 block
的元素,它應(yīng)該是 塊級(jí)元素
的一個(gè)子集,而不是等同的,一個(gè) 塊元素
是一個(gè) 塊級(jí)元素
,但一個(gè) 塊級(jí)元素
不一定是一個(gè) 塊元素
,所以不要混淆。
塊級(jí)元素生成塊級(jí)框,這些框會(huì)參與某些 BFC
。每個(gè)塊級(jí)元素都會(huì)生成一個(gè)主要的塊級(jí)框來(lái)包含其子框和生成的內(nèi)容,同時(shí)任何定位方式都會(huì)與這個(gè)主要的塊級(jí)框有關(guān)。
某些塊級(jí)元素還會(huì)在主要的塊級(jí)框之外產(chǎn)生額外的框:例如 list-item
元素,它需要生成一個(gè)額外的框用于包含 list-style-type
。這些額外的框會(huì)相對(duì)于主要的塊級(jí)框來(lái)進(jìn)行排版。
一個(gè) 塊容器框
要么只包含 塊級(jí)框
,要么創(chuàng)建一個(gè) IFC
而只包含 行內(nèi)級(jí)框
,但不能同時(shí)包含 塊級(jí)框
和 行內(nèi)級(jí)框
。
除了 table框
和 置換元素
,一個(gè) 塊級(jí)框
同時(shí)也是一個(gè) 塊容器框
。非置換的行內(nèi)塊
和 單元格
是 塊容器
但不是 塊級(jí)框
。
并不是所有的 塊級(jí)框
都是 塊容器框
,也并不是所有的 塊容器框
都是 塊級(jí)框
。
塊級(jí)框
和 塊容器框
的另外一個(gè)重要的區(qū)別是:塊級(jí)框
需要能夠包含其生成的內(nèi)容,但 塊容器框
并不需要。這是什么意思呢?簡(jiǎn)單的解釋一下:
比如一個(gè)
iframe
其內(nèi)容由src
屬性所決定,這可以當(dāng)成是生成的內(nèi)容,所以iframe
是一個(gè)塊級(jí)框
但卻不是塊容器框
簡(jiǎn)要的來(lái)說(shuō),是 塊容器
的 塊級(jí)框
稱之為 塊框
。
可以通過(guò)下面這個(gè)圖來(lái)快速的梳理清楚這3者之間的聯(lián)系:
(圖一)
說(shuō)完了塊級(jí)框,接下來(lái)說(shuō)說(shuō)行內(nèi)級(jí)框
行內(nèi)級(jí)元素是那些不會(huì)為自身內(nèi)容形成新的塊,而讓內(nèi)容分布在多行中的元素。display
屬性的:inline
, inline-table
, inline-block
, inline-flex
, inline-grid
值都可以將一個(gè)元素設(shè)置成行內(nèi)級(jí)元素。
如同塊元素之于塊級(jí)元素的關(guān)系,行內(nèi)元素僅僅是 display
屬性值為 inline
的元素,這里不再贅述。
行內(nèi)級(jí)元素生成行內(nèi)級(jí)框,而這些框會(huì)參與某個(gè) IFC
。一個(gè) 行內(nèi)框
是 行內(nèi)級(jí)框
,且其內(nèi)容參與了包含它的 IFC
。一個(gè) display
值是 inline
的非置換元素會(huì)生成一個(gè)行內(nèi)框。那些不是行內(nèi)框的行內(nèi)級(jí)框(例如行內(nèi)級(jí)置換元素、行內(nèi)塊元素、行內(nèi)表格元素)被稱為 原子行內(nèi)級(jí)框
,因?yàn)樗鼈兪且詥我徊煌该骺虻男问絹?lái)參與其 IFC
的。
細(xì)心的你會(huì)發(fā)現(xiàn)并沒(méi)有一個(gè) 行內(nèi)容器框
與 塊容器框
相對(duì)應(yīng),但卻多了一個(gè) 原子行內(nèi)級(jí)框
。并且有趣的是行內(nèi)塊
(包括置換和非置換元素)是原子行內(nèi)級(jí)框
,而非置換行內(nèi)塊
卻同時(shí)還是塊容器框
。
(圖二)
匿名框
包括 匿名塊框
和 匿名行內(nèi)框
。
假設(shè)一個(gè) div
中包含有一個(gè) p
和一段純文本 xxx
。由于 塊容器框
只允許要么包含 塊級(jí)框
,要么包含 行內(nèi)級(jí)框
,所以,為了符合這種情況,div
會(huì)生成一個(gè)匿名的塊級(jí)框用于包裹 xxx
,這個(gè)匿名框就叫做 匿名塊框
。
我們拿 W3C
上的一個(gè)例子來(lái)加深對(duì)匿名塊框的印象:
<div>
Some text
<p>More text</p>
</div>
(圖三)
與此同時(shí),我們將上面的代碼稍微改一下,將 p
變成 span
:
<div>
Some text
<span>More text</span>
</div>
div
生成一個(gè)塊框,More text
由 span
生成一個(gè)行內(nèi)框,由于 Some text
沒(méi)有與之相關(guān)的行級(jí)元素,將由 div 為其生成一個(gè)行內(nèi)框用以包裹,這個(gè)框稱為匿名行內(nèi)框。如圖四:
(圖四)
假設(shè)一個(gè)匿名框的類型可根據(jù)上下文來(lái)清晰界定,則 匿名行內(nèi)框
和 匿名塊框
都可被簡(jiǎn)稱為 匿名框
。
匿名框的繼承屬性會(huì)從包含它的非匿名框那里繼承,非繼承屬性取其初始值。
視口
。用戶代理可以在視口大小被調(diào)整時(shí)改變文檔的布局。如果視口小于渲染文檔的畫(huà)布區(qū)域,用戶代理應(yīng)當(dāng)提供一個(gè)滾動(dòng)機(jī)制。每個(gè)畫(huà)布只能擁有一個(gè)視口,但用戶代理可以把文檔渲染至多個(gè)畫(huà)布上(即為相同文檔提供不同的視圖)。
更多建議: