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