最開始學習CSS的時候,我一度認爲CSS基礎很簡單,可是CSS佈局是一塊難啃的骨頭。又到後來,我去亞馬遜買了暢銷書HTML and CSS, design and build websites,書上內容淺顯易懂,可是關於CSS佈局,也就只有一章,並且彷佛也沒有提到複雜的文檔流,我印象中也並不知道'BFC', 'Stacking Contexts'這些名詞。css
最近的複習中不斷出現'負margin','BFC','Stacking Contexts'等等概念,又在MDN上了解到CSS Visual Formatting Model,我以爲有必要系統地梳理一遍思路。html
本文以MDN Visual Formatting Model 這篇文章做爲引導,並加入本身的理解和新增的知識點,不會涉及太多的佈局真實場景,例如雙飛翼佈局,聖盃佈局,多列等高佈局等等,這裏只做爲基礎。web
CSS標準盒子模型是呈現每個獨立元素的基礎,組合起來構成文檔流ide
如下是一個標準的盒子,由4個部分組成佈局
標準盒模型咱們設置width
屬性的時候,width = content-width
,怪異盒模型width = content-width + padding-width + border-width
。post
當咱們設置背景色或者背景圖片時,默認會延伸到border外圍,可是Z-Ordering的順序在border如下,也就是說,若是同時設置了background
和border
屬性,border區域仍是顯示border,可是其Z-Order
如下是background
。咱們可使用background-clip屬性改變這一默認行爲,具體再也不敘述。學習
<p>test</p>
<p>test</p>
<a href="">test</a>
<a href="">test</a><br />
<a href="">test</a>
<a href="">test</a>
複製代碼
p, a {
width: 100px;
height: 40px;
border: 1px solid red;
margin: 20px;
padding: 30px;
}
複製代碼
圖一
圖二
仔細看上面兩幅圖,塊級和行級元素盒子有如下幾點不一樣flex
僅僅瞭解完每一個元素本身造成的盒子模型是不夠的,由於自身的盒子在某些時候還會受到容器盒子(Containing Block)的影響,例如ui
width
,height
,margin
,padding
,這裏須要注意,除了height
是基於父元素盒子的height
以外,其他三個屬性都是基於父元素盒子的width
top
,left
等等,此時是基於父元素盒子border內側進行定位關於容器盒子,咱們最常認爲它就是父元素的content部分,其實否則,有以下三種狀況spa
static
或者是relative
,則其Containing Block爲父元素的content部分absolute
,則其Containing Block爲第一個position不爲static
的父元素的content+padding部分,若是都是static
,則爲Initial Containing BlockInitial Containing Block
The initial containing block has the dimensions of the viewport, and is also the block that contains the
html
element. Simply put, the absolutely positioned element will be contained outside of thehtml
element, and be positioned relative to the initial viewport.簡而言之,就是視窗(Viewport)
fixed
,則其Containing Block爲視窗(Viewport)知道標準盒子模型以及容器盒子模型後,須要用必定的規則將這些盒子「組裝」起來,如下咱們來看看「組裝」方式
一旦盒子模型建立成功,接下來即是將這些盒子按照必定規則組裝起來,默認的組裝規則就是Normal Flow
使用position: relative
或者默認的position: static
,且沒有設定浮動,此時元素就是在Normal Flow中
Normal Flow中,塊級元素盒子垂直方向一個挨着一個,行級元素盒子水平方向一個挨着一個,一行不夠以後換到下一行
若是使用position: relative
,能夠將盒子基於原來的位置,經過設定top
,bottom
,left
,right
進行位移
設置一個元素爲浮動以後,這個元素盒子在一行中移動到最左邊或者最右邊,而且脫離Normal Flow
浮動元素對其後面的元素或者是其父元素都會產生影響,除非其後元素使用clear
屬性清除這一影響,我以前寫過一篇從聖盃和雙飛翼看浮動流的文章,裏面詳細解釋了浮動流的過程。
在Floats中,雖然盒子脫離了文檔流,可是其對於以後的元素盒子或者是父元素盒子都會產生影響,除非影響被清除。可是在Absolute Positioning Scheme中,盒子能夠說徹底抽離Normal Flow,且再也不對其餘元素產生影響
此時元素盒子的位置徹底基於其容器盒子(Containing Block),主要兩種狀況
position: absolute
,容器盒子爲第一個position不爲static
的父元素的content+padding部分position: fixed
,容器盒子爲視窗(Viewport)前面提到的都是元素應該出如今文檔中的位置,可是若是發生堆疊,那麼顯示順序(Z-Ordering, or Stacking Ordering)是怎麼樣的呢?
HTML文檔默認顯示給咱們的是第0層,這也是z-index
的默認值,爲0
正常的堆疊順序,遵循以下幾個規則(順序由底向上,若是發生重疊,只有最上的元素能被用戶看到)
<html>
)的background
和border
,在堆底position: static
),根據在HTML文檔出現順序,後面出現的在堆頂static
),根據在HTML文檔出現順序,後面出現的在堆頂display: flex
,且對flex container下的子元素使用order
屬性改變順序,也會影響到堆疊順序,order
最高的元素出如今堆頂依據上面的規則,咱們看一個例子
5個DIV在文檔的出現順序爲1,2,3,4,5首先來看看z-index
的定義
The z-index CSS property specifies the z-order of a positioned element and its descendants or flex items (children of an element with display: flex). When elements overlap, z-order determines which one covers the other. An element with a larger z-index generally covers an element with a lower one.
也就是說,z-index
只能在flex-item或者positioned-items下設置纔有效,不然無效
再看一個例子(在上一個例子基礎上使用z-index
)
其實咱們使用z-index
,其實是造成了一個Stacking Context,不一樣的Stacking Context下的元素層疊順序互不影響,它們之間的層疊順序由上層元素之間的層疊順序決定
建立Stacking Context有以下幾種常見方法
<html>
建立了默認的Stacking Contextposition: fixed
或者absolute
的元素,且z-index
值不爲默認值auto
display: flex
container下的子元素,且z-index
值不爲默認值auto
opacity
值小於1的元素前面提到過,不一樣的Stacking Context下的元素層疊順序互不影響,它們之間的層疊順序由上層元素之間的層疊順序決定
z-index
的initial(默認值)爲auto
auto
The box does not establish a new local stacking context. The stack level of the generated box in the current stacking context is the same as its parent's box.
也就是說,若是一個元素沒有建立Stacking Context,則其順序由父級Stacking Context決定,最頂層的Stacking Context爲根元素<html>
建立,其z-index值爲0
仍是先看一個例子,下面分別是文檔結構和結果圖
Root
到這裏Document Flow和CSS Formatting Model也就結束了,涵蓋了基本的佈局規則。只有深刻理解這些基礎,才能更好地去理解之前的一些佈局Trick,好比雙飛翼佈局,聖盃佈局等等,這些佈局創建在這些基礎上,若是理解了這些內容,本身實現一些佈局Trick也不是不可能,雖然如今Flex佈局已經能夠解決不少問題了