萬事起頭難,只要不起頭,就一點都不難了。
在這個充滿著 CSS Frameworks 的年代,人人有功練,人人有版切,身為老屁股的我只能在沙灘上曬乾,而且還賣不到錢。
鐵人賽就當作自己還有在喘氣的證明。
其實寫 CSS 框架應該比較多觀眾,但就一個碼農來說,自己動手做會比較有趣一點。而且那些框架實在有點五花八門,就是你去 Google 一些關鍵字,諸如「超好用」「XX 天就上手」「20XX 熱門框架」然後就會跑出一堆。
我沒有阻止你用,只要能賺錢的框架就是好框架。
君不見 jQuery 的
$
還是屹立不搖。
不過 jQuery 有點離題了就是。
目前 w3c 對於 Flexbox, Grid 這兩件事情算是有認真在更新。雖然說 Grid 已經 CR 不過又掛上 Draft,該吵的東西也還沒有結論(例如 subgrid
會推遲到 Level 2 才可能會推出 #Issue958)。
Grid 從 2016 年 CR 至今也 5 個年頭了,基本上在 Caniuse 上面也呈現出不錯的支援度。熱門的 TailwindCSS 基本上也有採用 Grid 來做排版,至於怎麼用不要來問我,我沒有很熟(哈)。
Flexbox 就不用再多說,我在 2012 年看他 CR 後,又到了 2016 才慢慢被推廣出來,算起來已經 9 年了。至於說為什麼那麼不紅(或是不普及?),可能要去問一下前陣子才入土的 IE 吧。
至於所搭配的 Media Query 會在系列中提及,會順便講一點,不會著墨太多。
flex-basis
的魔術align-self
order
gap
grid-template-areas
的字串定義fr
fit-content(limit)
minmax(min, max)
<軌道格線>
<數字> <自訂軌道名稱>
span [<數字>, <自訂軌道名稱>]
auto
與 Grid 單元軌道重疊
stretch
)與留白(margin
)以上這些,其實就把超長篇幅的文章然後分割成 30 份這樣吧(哈)。
其實我不知道 Flexbox 還有誰想看?
這年頭好像用框架比較快,誰理你背後的原理是什麼呢?
我們先來看看可使用狀況。基本上除了 IE 以外,是不用擔心使用上的問題。
Flexbox 的基本盤是對應從 CSS2.1 以來的四種編排模式,
block
)inline
, inline block
)table
, 或各種資料集設計)position
的各種變化)雖然是這樣講,不過這就跟當年 CSS1/2/2.1 開始流行後,從 <table>
慢慢轉向 <div>
後,接著到了 HTML5 開始講語意化。出了一些很奇妙的事情,
<table>
退流行了所以我都用 <div>
很潮~<div>
就用 position
神馬都可以排,超 DUE 的~float
簡直凌波微步,我得意的飄~<div>
簡直罪惡!其他的就不提了,我只想說,為了語意化而語意化真的挺噁心的。
Flexbox 區塊元件主要構成如下,
如果你把 Flex 容器主軸方向設定為 column
的時候,上圖的主要軸、交叉軸就會交換。
設定容器我們可以使用 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 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
[CSS] Flex/Grid Layout Modules, part 1
(html、CSS、js)中的絕大部分項目、屬性和作用,理解上頗為抽象,
網路上多是文字或圖文解說的模式,作者雖然辛苦撰寫,讀者卻常處於閱讀障礙,半知不解。
其實作者只需再加一塊拼圖就可完美 - 提供線上範例(codepen、jsfiddle..),看css-trick這麼受人喜好正是如此。