其實我不知道 Flexbox 還有誰想看?
這年頭好像用框架比較快,誰理你背後的原理是什麼呢?
Flexbox
我們先來看看可使用狀況。基本上除了 IE 以外,是不用擔心使用上的問題。
Flexbox 的基本盤是對應從 CSS2.1 以來的四種編排模式,
- 區塊(
block
) - 行內(
inline
,inline block
) - 表格資料(
table
, 或各種資料集設計) - 定位區塊(使用
position
的各種變化)
雖然是這樣講,不過這就跟當年 CSS1/2/2.1 開始流行後,從 <table>
慢慢轉向 <div>
後,接著到了 HTML5 開始講語意化。出了一些很奇妙的事情,
<table>
退流行了所以我都用<div>
很潮~<div>
就用position
神馬都可以排,超 DUE 的~float
簡直凌波微步,我得意的飄~- HTML5 說要語意化,用
<div>
簡直罪惡!
其他的就不提了,我只想說,為了語意化而語意化真的挺噁心的。
基本介紹
Flexbox 區塊元件主要構成如下,
- Flex 容器(Container)
- Flex 元件(Items)
- 容器尺寸(通常我們叫做 寬度)
- 交叉軸尺寸(通常我們叫做 高度)
- 容器主軸/交叉軸(依據排列方式決定哪一個方向為主軸)
如果你把 Flex 容器主軸方向設定為 column
的時候,上圖的主要軸、交叉軸就會交換。
Flex 容器
設定容器我們可以使用 display
來達成,容器可以設定成兩種,
display: flex
亦即使用區塊(Box Level)來設定容器。display: inline-flex
亦即使用行內(Inline Level)來設定容器。
無輪你設定的是哪一種,需要留意 Flex 容器會忽略以下特性,
float
,clear
會被忽略。vertical-align
無法應用在 Flex 元件上。::first-line
,::first-letter
這兩個擬似元件無法套用至容器上。
倘若元素指定
display: inline-flex
的話,在計算樣式值(Computed Value)會呈現flex
而不是inline-flex
,這一點請留意。
樣式設定
在容器當中,以下列舉常用的樣式設定,
樣式 | 值 | 預設值 |
---|---|---|
flex-direction |
row , row-reverse , column , column-reverse |
row |
flex-wrap |
nowrap , wrap , wrap-reverse |
nowrap |
flex-flow |
<flex-direction> <flex-wrap> |
無預設值 |
容器主要軸、交叉軸會因為方向性的不同而交換,其下屬性所適用的方向也會不同。
另,軸方向也會因為
writing-mode
的影響而有不一樣的呈現,關於 Write Mode 可以參考 w3c 上面的說明(CSS Writing Modes Level 4)。
容器中對於影響元件的屬性有這些,
樣式 | 值 | 預設值 |
---|---|---|
justify-content |
flex-start , flex-end , center , space-between , space-around |
flex-start |
align-items |
flex-start , flex-end , center , baseline , stretch |
stretch |
align-content |
flex-start , flex-end , center , space-between , space-around , stretch |
stretch |
需要留意的是 align-content
只能適用在多行的 Flex 容器當中,在預設的容器設定中使屬於單行 Flex 容器,套用這個樣式是無效的設定。
軸方向
容器些樣式設定會因為軸方向性的不同而應用在不同的方向上(會跟著軸轉動)。請留意一個點,軸方向並不總是內容流向,我所舉的例子都是以慣用方向為主(由左至右,由上到下)。
舉個例子來說,
另外關於 align-content
則是在多行容器中才會套用到這個樣式。所謂的 多行 的意思即是 wrap
的情況下,產生超過一行的 Flex 元件時,該樣式就會被套用。
請留意
column
這個方向在沒有容器尺寸的情況下,無法產生wrap
的效果,亦即並無 多行 的情況存在,且關於wrap
的相關樣式也會失效。
舉一個套用 wrap
產生多行 Flex 容器的例子,
跟其他兩個樣式相同,當軸方向轉動時,align-content
也會跟著軸轉動,亦即應用的方向會不同。
Flex 元件
任何被 Flex 容器所包含的第一層子元件,都會被轉成 Flex 元件,而自身屬性會轉換成 Flex 格式內容(Flex formatting context),可以當作一般區塊元件看待,但實際上並不是(Like Box Model, bot NOT.)。如同上述所說,這些元件並無法使用 float
爾等設定,這一點需特別留意。另外,假設這些元件被定義了靜態定位(position
為 static
, absolute
)時,該元件就不屬於 Flex 容器預設的主軸流向,會跳脫任何關於 Flex 容器所帶來的影響。
元件自身也可以使用 display: flex
來將自己轉變成容器,這樣的作法在需要複雜結構時,可以自由變化使用。
樣式設定
Flex 元件有以下樣式可以使用,
樣式 | 值 | 預設值 |
---|---|---|
flex-grow |
數字(負值無效) | 0 |
flex-shrink |
數字(負值無效) | 0 |
flex-basis |
auto , content 或 寬度 |
auto |
flex |
none 或 <flex-grow> <flex-shrink> <flex-basis> |
0 1 auto |
order |
數字(可為負值) | 0 |
align-self |
auto , flex-start , flex-end , center , baseline , stretch |
auto |
其中 flex
除了 none
外,還有幾個關鍵字可以使用,
關鍵字 | 等值 |
---|---|
none |
0 0 auto |
initial |
0 1 auto |
auto |
1 1 auto |
<正整數> |
<正整數> 1 0 |
flex
, flex-grow
, flex-shrink
, flex-basis
在絕大多數的 CSS 框架中,我們比較常見的設定大多都是這些組合,
flex: 0 1 auto;
// 或
flex: 1 0 100%;
// 或
flex: 1 0 50%;
max-width: 50%;
然後就沒有然後了。因為人家這樣用所以你就跟著這樣用,至於為什麼要這樣用好像也不是挺重要的事情。
沒關係,我們就來看看到底發生了什麼事情?
屬性 | 說明 |
---|---|
flex-grow |
將元件依照此設定數字的權重來填滿容器的剩餘空間。 |
flex-shrink |
當容器剩餘空間不足時,依照此權重來壓縮元件。 |
flex-basis |
在水平(row )排列容器中,等同於 width 樣式,在同時設定時將會忽略 width 的樣式設定。但若為 auto 或 content 時,則 width 樣式將會覆蓋。而當你設定為 0 時,結果會跟 content 雷同,但權重不同。 |
flex-grow
計算方式,可以依照此公式來計算,
剩餘空間 x <flex-grow> / sum(<flex-grow>)
剩餘空間怎麼來的呢?
容器空間 - sum(<flex-basis>||<width>)
但是,
當你的 flex-grow
總和小於 1
的時候,事情就不是這樣了。在所有 Flex 元件的 flex-grow
總和小於 1
時,該總和會直接當作 1
來使用。換句話說,上面的公式會變成,
剩餘空間 x <flex-grow> / 1
這樣計算下來,容器就可能會有剩餘空間沒有分配的情況。
另外,當你的 flex-grow
有搭配 max-width
使用時,所計算出來的元件若大於 max-width
,則會優先取用 max-width
的設定值來使用,計算出來的填滿尺寸將會被忽略。這也是造成容器沒有被填滿的另外一個原因。
flex-shrink
計算方式,可以依照此公式來計算,
溢出空間 x <flex-shrink> * <width>) / sum(<flex-shrink> * <width>)
溢出空間的計算方式為(注意,這為負值),
容器空間 - sum(<flex-basis>||<width>)
與 flex-grow
雷同,當你的 flex-shrink
總和小於 1
的時候,他並不會拿所有的溢出空間來計算,你的真實的溢出空間要先經過這樣的計算,
溢出空間 x sum(<flex-shrink>) / 1
算出新的溢出空間之後,才回頭套用上面的公式去計算。
flex-basis
的魔術
特別把這件事情拿出來講的原因,是因為他跟 width
實在有說不清的愛恨糾葛。如同上述提及了一些優先權的事情,這邊給一個比較清楚的比較表,
設定 | 寬度有效值 |
---|---|
flex-basis: 50px; |
50px |
flex-basis: 50px; width: auto; |
50px |
flex-basis: content; width: 60px; |
60px |
flex-basis: 70px; width: 60px; |
70px |
flex-basis: auto; width: 80px; |
80px |
flex-basis: 90%; width: 80px; |
90% |
flex-basis: 90%; max-width: 80%; |
80% |
基本上,只要 flex-basis
不是使用關鍵字 auto
, content
的情況下,優先權一律覆蓋 width
的設定。但是,這個數值設定會受到 max-width
的影響而有所不同。
align-self
這個 Flex 元件屬性有一個 必要條件,倘若以 row
為主軸方向,你的容器必須要有交叉軸的尺寸設定,不然這個屬性是無法有效呈現的。
order
故名思義就是 Flex 元件順序的設定,但請留意,如果你的元件使用了靜態定位設定(position
為 static
, absolute
)時,因為元件會跳脫 Flex 主軸流向,所以此時的順序設定會失效。
Flex 元件會有一個隱性的定義,在 order
樣式混用的情況下,沒有設定 order
樣式的 Flex 元件,會帶有一個 order: 0
的效果。所以,若你在多個元件使用 order
時,請務必確認每個元件都有設定你想要的 order
樣式。
舉例來說,
<div class="flex">
<div class="item item-1"></div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>
.flex {
display: flex;
flex-flow: row;
}
.item {
flex: 1 0 33.333333%;
max-width: 33.333333%;
}
.item-1 {
order: 1;
}
.item-2 {
order: 3;
}
.item-3 {
order: 2;
}
最終呈現的結果如圖,
有一點請留意,如果你的軸方向是反向(row-reverse
或 column-reverse
)的話,順序的設定也會反過來。
小記
以上這些是 Flexbox 的基本概念介紹,其實講起來並沒有很多艱深的東西,真正比較枯燥乏味的會再後面繼續介紹,如果不想理解 Flexbox 的演算機制的可以跳過沒關係(笑)。
本篇內容理論上可以應付五成以上的容器設定。為什麼只有五成?因為我還有 留白 的部分沒有講到,那些算一算大概是剩下的四成五左右。
下一篇會著墨於那個四成五,至於剩下的 5% 就放最後吧,反正都是一些很硬的演算機制。
目錄與小節:
[CSS] Flex/Grid Layout Modules, part 0