- 首發:krissarea.gitee.io
- 作者:陳大魚頭
- github: KRISACHAN
正常流
什麼是“正常流”? 其實就是我們日常所說的“文件流”。 在W3C官方文件裡對應的是“normal flow”。
正常流的盒子屬於格式化上下文(FC),在CSS2.2中可以是表格、塊或內聯。 在CSS3中引入了flex跟grid,當然以後會引入得更多。
塊級盒子(block-level boxes) 與建立 塊級格式化上下文(BFC) 有關;
行內級盒子(inline-level boxes) 與建立 行內級格式化上下文(IFC) 有關。
BFC
魚頭注:在之前的文章中有介紹過如何生成一個BFC,本章便不再累述。
根據W3C上的解釋:
浮動、絕對定位元素、塊容器(例如inline-blocks、table-cells、and table-captions)都不是塊盒子。除了overflow
以外的visible
(除非該值已經傳播到了視口)為其內容建立新的BFC。
表現是什麼?
表現就是在包含塊內一個盒子一個盒子不重疊地垂直排列,兩個兄弟盒子直接的垂直距離由margin
決定。浮動也是如此(雖然有可能兩個盒子的距離會因為floats
而變小),除非該盒子再建立一個新的BFC。
簡單來說,BFC就是一個獨立不干擾外界也不受外界干擾的盒子啊(/ω\)
IFC
魚頭注:Mmmmm,BFC還是相對好理解,IFC比較複雜,W3C上所佔的篇幅也比BFC多得多的。
簡單來說,跟BFC表現不一樣的盒子就是IFC了(*❦ω❦)。
跟BFC不一樣,IFC內的盒子會從包含塊的頂部一個接著一個地水平排列。這些盒子會考慮水平margin
,border
跟padding
。垂直對齊的方式也略有複雜。然後,包含形成一條線的框的矩形區域稱為線盒(line box)。
線盒(line box)的寬度:由浮動情況跟它所在的包含塊決定。
線盒(line box)的高度:由line-height
的計算結果決定。
基線(baseline)
線盒(line box) 的高度由line-height
的計算結果決定。
line-height
的定義就是線盒(line box)內兩基線(baseline)(W3C原文)的間距。
vertical-align
的預設值就是基線。
字母x
你們還記得讀書時用的英語作業本嗎?
如上圖所示,我們看到小寫字母x的位置,它的上下邊緣就是我們的基線(baseline),但下邊緣才是我們日常使用的屬性值。順便一提,CSS單位ex
便是指的這個字母x的高度。
如何理解IFC
自從翻了CSS的發展史之後,瞭解了CSS的誕生背景之後,其實很多東西理解起來就輕鬆了。IFC之所以比BFC複雜,原因就在於很多非規律的成分,在西文了,我們可以簡單粗暴的理解為英語作業本的表現,但是在writing-mode不同,文字表現不同的各個國家,IFC的表現也會有差異。
當然以上都是我的個人理解,如果有更科學更標準的理解方式或者不同的想法,可以加魚頭微信“krisChans95”來探討。
層疊上下文與層疊順序
我們首先來看一張很著名的圖
上面便是在同樣的上下文中,元素的層疊規則(CSS3以後的除外,那規則會比較複雜)。元素的 z-index 值只在父級層疊上下文中有意義。級層疊上下文被自動視為父級層疊上下文的一個獨立單元。
文件中的層疊上下文由滿足以下任意一個條件的元素形成:
- 根元素 (HTML),
- z-index 值不為
auto
的 絕對/相對定位, - 一個 z-index 值不為
auto
的 flex 專案 (flex item),即:父元素display: flex|inline-flex
, opacity
屬性值小於 1 的元素,transform
屬性值不為none
的元素,mix-blend-mode
屬性值不為 "normal"的元素,filter
值不為none
的元素,perspective
值不為none
的元素,isolation
屬性被設定為isolate
的元素,position: fixed
- 在
will-change
中指定了任意 CSS 屬性,即便你沒有直接指定這些屬性的值 -webkit-overflow-scrolling
屬性被設定touch
的元素
新時代的佈局
Flex
我想到如今,應該很少人會沒寫過或者沒了解過 Flex (不知道的可以翻閱MDN)。
這個是 CSS 史上第一個以 start-end 來定義方向的屬性,這是一個可伸縮的佈局模型。
一個設有 display:flex
或 display:inline-flex
的元素是一個伸縮容器,伸縮容器的子元素被稱為為伸縮專案,這些子元素使用伸縮佈局模型來排版。
語法如下:
display: flex/inline-flex;
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ];
複製程式碼
flex
屬性可以指定1個,2個或3個值。
單值語法: 值必須為以下其中之一:
- 一個無單位 數(
<number>
) : 它會被當作<flex-grow>的值
。 - 一個有效的 寬度(width) 值: 它會被當作
<flex-basis>的值
。 - 關鍵字
none
、auto
, 或initial
。
雙值語法: 第一個值必須為一個無單位數,並且它會被當作 <flex-grow>
的值。第二個值必須為以下之一:
- 一個無單位數:它會被當作
<flex-shrink>
的值。 - 一個有效的寬度值: 它會被當作
<flex-basis>
的值。
三值語法:
- 第一個值必須為一個無單位數,並且它會被當作
<flex-grow>
的值。 - 第二個值必須為一個無單位數,並且它會被當作
<flex-shrink>
的值。 - 第三個值必須為一個有效的寬度值, 並且它會被當作
<flex-basis>
的值。
Grid
我印象中第一次接觸Grid佈局的時候,開個Chrome的實驗性功能也就只能能支援個repeat(4, 200px)
,但如今已經除了IE,其他瀏覽器差不多也是Full support了(如果你還不瞭解這個佈局模型,可以翻閱MDN)。
在這裡順便提一下,Flex是一維佈局,Grid是二維佈局。意思就是Flex只能同時在一個方向進行作用,而Grid卻可以在縱橫兩個方向同時工作。
語法如下:
display: grid/inline-grid;
gird: <'grid-template'> | <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>? | [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
複製程式碼
我們來看看 grid 所支援的一些 “奇怪” 的特性:
名稱空間:
魚頭覺得 grid 容器中最有趣的功能就是名稱空間了,我們可以看看以下示例:
首先是第一種 網格線命名:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
.grid {
display: grid;
width: 420px;
background: #e4d6ba;
margin: 1em auto;
}
.g-namespace {
height: 400px;
grid-template-columns: [col1] 100px [col2] auto [col3] 100px;
grid-template-rows: [rows1] 25% [rows2] 100px [rows3] auto [rows4] 60px
}
.grid > div {
outline: 1px dotted;
}
</style>
<body>
<div class="grid g-namespace">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</body>
複製程式碼
效果如下:
第二種 真名稱空間佈局:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
.grid {
display: grid;
width: 400px;
height: 400px;
margin: 1em auto;
}
.g-namespace {
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-template-areas: "頭部 頭部 頭部" "左邊 中間 右邊" "底部 底部 底部";
}
.頭部 {
grid-area: 頭部 / 頭部 / 頭部 / 頭部;
background: #32CD32;
}
.底部 {
grid-area: 底部 / 底部 / 底部 / 底部;
background: #FFD700;
}
.左邊 {
grid-area: 左邊 / 左邊 / 左邊 / 左邊;
background: #EE82EE;
}
.右邊 {
grid-area: 右邊 / 右邊 / 右邊 / 右邊;
background: #FF7F50;
}
</style>
<body>
<div class="grid g-namespace">
<div class="頭部"></div>
<div class="左邊"></div>
<div class="右邊"></div>
<div class="底部"></div>
</div>
</body>
複製程式碼
效果如下:
通過上面兩個示例,我們可以發現Grid佈局的二維性可以滿足我們日常很多的佈局要求,當然,第一眼看語法不免有點懵,但是熟悉之後,基本日常需求中的二維佈局我們都能依賴它來完成。
一些常用的靈活尺寸
屬性 | 定義 |
---|---|
fr | 可伸縮長度單位,網格容器中可用空間的一等份。 |
auto | 自由分配,由具體情況決定。 |
minmax() | 定義了一個長寬範圍的閉區間。 |
fit-content() | 同等於min(maximum size, max(minimum size, argument)) |
以上屬性對比結果如下:
原始碼在我codepen中,大家可以自行去對比: codepen.io/krischan77/…
後記
本章的內容要深究起來是非常龐大的,魚頭我在準備內容的時候有想過是不是要另外再開個佈局的系列去分享,但是我想把本文當成是一個關鍵字集合來供自己以及有需要的人來做目錄也是極好的。我認為 CSS 中最難的部分就是佈局了,雖然W3C本身提供了很多的屬性以及規範來處理這些佈局問題的,但是涉及到了現實的專案,更多時候是錯綜複雜的,但是隨著 CSS 邏輯屬性的變化,以及各類新佈局系統的出現,相信以後的佈局會簡單得多。
本章內容就這麼草草結束了,關於上面提到的,或者沒有提到的與之相關的,以後有機會魚頭會新開個系列來分享。當然如果看到這裡的你有任何佈局上的見解或問題也歡迎來找魚頭探討。
參考資料:
CSS Flexible Box Layout Module Level 1
CSS Grid Layout Module Level 1
CSS Box Alignment Module Level 3
【Hello CSS】系列
【Hello CSS】
是以CSS
基礎概念為主題的系列文章,旨在幫助大家更深刻地瞭解並且提高CSS
在各位開發者心目中的地位。由於魚頭我水平有限,文筆有限,如果各位在文章中發現有任何不合理,不正確的地方,還煩不吝指出,我會非常感謝的;如果通過文章有任何想法或疑問,也希望各位能積極留言,我們互相探討;如果通過本系列文章有所收穫,這就讓魚頭我喜不自勝了!
如果你也喜歡`CSS`,喜歡探討技術,或者對本文,本系列有任何的意見或建議,魚頭非常希望你能加入一個有趣的微信群 — “進擊的CSS”。你可以掃描下方二維碼,新增魚頭微信,新增時註明 “加群”,如果你覺得我的文章有趣,歡迎關注微信公眾號“魚頭的Web海洋”。衷心希望可以遇見你。
下一篇
第七章-CSS的繼承與可變性