大家好,我是樹哥!
前面一篇文章整體介紹了 CSS 的佈局知識,其中說到 float 佈局是 CSS 不斷完善的副產物。而在 2023 年的今天,flex 這種佈局方式纔是未來!那麼今天我們就來學習下 flex 彈性佈局。
什麼是 Flex 佈局?
在經過了長達 10 年的發展之後,CSS3 才終於迎來了一個簡單好用的佈局屬性 —— flex。Flex 佈局又稱彈性佈局,它使用 flexbox 屬性使得容器有了彈性,可以自動適配各種設備的不同寬度,而不必依賴於傳統的塊狀佈局和浮動定位。
舉個很簡單地例子,如果我們想要實現一個很簡單左側定寬,右側自適應的導航佈局,如下圖所示。
在沒有 flex 之前,我們的代碼是這麼寫的。
<div>
<h1>4.1 兩欄佈局 - 左側定寬、右側自適應 - float</h1>
<div class="container">
<div class="left41"></div>
<div class="right41"></div>
</div>
</div>
/** 4.1 兩欄佈局 - 左側定寬、右側自適應 - float **/
.left41 {
float: left;
width: 300px;
height: 500px;
background-color: pink;
}
.right41 {
width: 100%;
height: 500px;
background-color: aquamarine;
}
這種方式不好的地方在於,我們還需要去理解 float 這個概念。一旦需要理解 float 這個概念,我們就會拖出一大堆概念,例如文檔流、盒子模型、display 等屬性(雖然這些東西確實應該學)。但對於 flex 來說,它就很簡單,只需要設置一個伸縮係數即可,如下代碼所示。
<div>
<h1>4.2 兩欄佈局 - 左側定寬、右側自適應 - flex</h1>
<div class="container42">
<div class="left42"></div>
<div class="right42"></div>
</div>
</div>
.container42 {
display: flex;
}
.left42 {
width: 300px;
height: 500px;
background-color: pink;
}
.right42 {
flex: 1;
width: 100%;
height: 500px;
background-color: aquamarine;
}
上面的代碼裏,我們只需要將父級容器設置爲 flex 展示形式(display: flex),隨後在需要自動伸縮的容器裏設置屬性即可。上面代碼中的 flex: 1
表示其佔據所有其他當行所剩的空間。通過這樣的方式,我們非常方便地實現了彈性佈局。
當然,上面只是一個最簡單的例子,甚至還不是很能體現出 flex 的價值。flex 除了在響應式佈局方面非常方便之外,它在對齊等方面更加方便,能夠極大地降低學習成本、提高工作效率。
Flex 核心概念
對於 Flex 佈局來說,其有幾個核心概念,分別是:主軸與交叉軸、起始線和終止線、Flex 容器與 Flex 容器項。
主軸和交叉軸
在 Flex 佈局中有一個名爲 flex-direction
的屬性,可以取 4 個值,分別是:
- row
- row-reverse
- column
- column-reverse
如果你選擇了 row 或者 row-reverse,那麼主軸(Main Axis)就是橫向的 X 軸,交叉軸(Cross Axis)就是豎向的 Y 軸,如下圖所示。
如果你選擇了 column 或者 column-reverse,那麼主軸(Main Axis)就變成是豎向的 Y 軸,交叉軸(Cross Axis)就是橫向的 X 軸,如下圖所示。
起始線和終止線
過去,CSS 的書寫模式主要被認爲是水平的,從左到右的。但現代的佈局方式涵蓋了書寫模式的範圍,所以我們不再假設一行文字是從文檔的左上角開始向右書寫的。
對於不同的語言來說,其書寫方向不同,例如英文是從左到右,但阿拉伯文則是從右到左。那麼對於這兩種語言來說,其xx會有所不同 TODO。舉個簡單的例子,如果 flex-direction 是 row ,並且我是在書寫英文。由於英文是從左到右書寫的,那麼主軸的起始線是左邊,終止線是右邊,如下圖所示。
但如果我在書寫阿拉伯文,由於阿拉伯文是從右到左的,那麼主軸的起始線是右邊,終止線是左邊,如下圖所示。
在 Flex 佈局中,起始線和終止線決定了 Flex 容器中的 Flex 元素從哪個方向開始排列。 舉個簡單例子,如果我們通過 direction: ltr
設置了文字書寫方向是從左到右,那麼起始線就是左邊,終止線就是右邊。此時,如果我們設置的 flex-direction
值是 row
,那麼 Flex 元素將會從左到右開始排列。但如果我們設置的 flex-direction
值是 row-reverse
,那麼 Flex 元素將會從右到左開始排列。
在上面的例子中,交叉軸的起始線是 flex 容器的頂部,終止線是底部,因爲兩種語言都是水平書寫模式。但如果有一種語言,它的書寫形式是從底部到頂部,那麼當設置 flex-direction
爲 column 或 column-reverse 時,也會有類似的變化。
Flex 容器與 Flex 元素
我們把一個容器的 display 屬性值改爲 flex 或者 inline-flex 之後,該容器就變成了 Flex 容器,而容器中的直系子元素就會變爲 flex 元素。如下代碼所示,parent 元素就是 Flex 容器,son 元素就是 Flex 元素。
<style>
#parent {
display: flex;
}
</style>
<div id="parent">
<div id="son"></div>
</div>
Flex 核心屬性
對於 Flex 來說,它有非常多的用法,但核心屬性卻相對較少。這裏我只簡單介紹幾個核心屬性,如果你想了解更多 Flex 的屬性,可以去 Mozilla 官網查詢,這裏給個傳送門:flex 佈局的基本概念 - CSS:層疊樣式表 | MDN。
對於 Flex 佈局來說,其核心屬性有如下幾個:
- flex-direction 主軸方向
- flex 伸縮係數及初始值
- justify-content 主軸方向對齊
- align-items 交叉軸方向對齊
flex-direction 主軸方向
如上文所介紹過的,flex-direction 定義了主軸的方向,可以取 4 個值,分別是:
- row 默認值
- row-reverse
- column
- column-reverse
一旦主軸確定了,交叉軸也確定了。主軸和交叉軸與後續的對齊屬性有關,因此弄懂它們非常重要!舉個很簡單的例子,如下的代碼將展示下圖的展示效果。
.box {
display: flex;
flex-direction: row-reverse;
}
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
如果你將 flex-direction 改成 column-reverse,那麼將會變成如下的效果,如下圖所示。
flex 伸縮係數及初始值
前面說到 Flex 佈局可以很方便地進行響應式佈局,其實就是通過 flex 屬性來實現的。flex 屬性其實是 flex-grow、flex-shrink、flex-basis 這三個參數的縮寫形式,如下代碼所示。
flex-grow: 1;
flex-shrink: 1;
flex-basis: 200px;
/* 上面的設置等價於下面 flex 屬性的設置 */
flex: 1 1 200px;
在考慮這幾個屬性的作用之前,需要先了解一下 可用空間 available space 這個概念。這幾個 flex 屬性的作用其實就是改變了 flex 容器中的可用空間的行爲。
假設在 1 個 500px 的容器中,我們有 3 個 100px 寬的元素,那麼這 3 個元素需要佔 300px 的寬,剩下 200px 的可用空間。在默認情況下,flexbox 的行爲會把這 200px 的空間留在最後一個元素的後面。
如果期望這些元素能自動地擴展去填充滿剩下的空間,那麼我們需要去控制可用空間在這幾個元素間如何分配,這就是元素上的那些 flex 屬性要做的事。
flex-basis
flex-basis 屬性用於設置 Flex 元素的大小,其默認值是 auto。此時瀏覽器會檢查元素是否有確定的尺寸,如果有確定的尺寸則用該尺寸作爲 Flex 元素的尺寸,否則就採用元素內容的尺寸。
flex-grow
flex-grow 若被賦值爲一個正整數,flex 元素會以 flex-basis 爲基礎,沿主軸方向增長尺寸。這會使該元素延展,並佔據此方向軸上的可用空間(available space)。如果有其他元素也被允許延展,那麼他們會各自佔據可用空間的一部分。
舉個例子,上面的例子中有 a、b、c 個 Flex 元素。如果我們給上例中的所有元素設定 flex-grow 值爲 1,容器中的可用空間會被這些元素平分。它們會延展以填滿容器主軸方向上的空間。
但很多時候,我們可能都需要按照比例來劃分剩餘的空間。此時如果第一個元素 flex-grow 值爲 2,其他元素值爲 1,則第一個元素將佔有 2/4(上例中,即爲 200px 中的 100px), 另外兩個元素各佔有 1/4(各 50px)。
flex-shrink
flex-grow 屬性是處理 flex 元素在主軸上增加空間的問題,相反 flex-shrink 屬性是處理 flex 元素收縮的問題。如果我們的容器中沒有足夠排列 flex 元素的空間,那麼可以把 flex 元素 flex-shrink 屬性設置爲正整數,以此來縮小它所佔空間到 flex-basis 以下。
與flex-grow屬性一樣,可以賦予不同的值來控制 flex 元素收縮的程度 —— 給flex-shrink屬性賦予更大的數值可以比賦予小數值的同級元素收縮程度更大。
justify-content 主軸方向對齊
justify-content 屬性用來使元素在主軸方向上對齊,它的初始值是 flex-start,即元素從容器的起始線排列。justify-content 屬性有如下 5 個不同的值:
- flex-start:從起始線開始排列,默認值。
- flex-end::從終止線開始排列。
- center:在中間排列。
- space-around:每個元素左右空間相等。
- space-between:把元素排列好之後,剩餘的空間平均分配到元素之間。
各個不同的對齊方式的效果如下圖所示。
flex-start:
flex-end:
center:
space-around:
space-between:
align-items 交叉軸方向對齊
align-items 屬性可以使元素在交叉軸方向對齊,它的初始值是 stretch,即拉伸到最高元素的高度。align-items 屬性有如下 5 個不同的值:
- stretch:拉伸到最高元素的高度,默認值。
- flex-start:按 flex 容器起始位置對齊。
- flex-end:按 flex 容器結束爲止對齊。
- center:居中對齊。
- baseline:始終按文字基線對齊。
各個不同的對齊方式的效果如下圖所示。
stretch:
flex-start:
flex-end:
center:
要注意的事,無論 align-items 還是 justify-content,它們都是以主軸或者交叉軸爲參考的,而不是橫向和豎向爲參考的,明白這點很重要。
Flex 默認屬性
由於所有 CSS 屬性都會有一個初始值,所以當沒有設置任何默認值時,flex 容器中的所有 flex 元素都會有下列行爲:
- 元素排列爲一行 (flex-direction 屬性的初始值是 row)。
- 元素從主軸的起始線開始。
- 元素不會在主維度方向拉伸,但是可以縮小。
- 元素被拉伸來填充交叉軸大小。
- flex-basis 屬性爲 auto。
- flex-wrap 屬性爲 nowrap。
弄清楚 Flex 元素的默認值有利於我們更好地進行佈局排版。
實戰項目拆解
看了那麼多的 Flex 佈局知識點,總感覺乾巴巴的,是時候來看看別人在項目中是怎麼用的了。
上面是我在 CodePen 找到的一個案例,這樣的一個佈局就是用 Flex 佈局來實現的。通過簡單的分析,其實我們可以拆解出其 Flex 佈局方法,大致如下圖所示。
首先整體分爲兩大部分,即導航欄和內容區域,這部分的主軸縱向排列的(flex-direction: column),如上圖紅框部分。隨後在內容區域,又將其分成了左邊的導航欄和右邊的內容區域,此時這塊內容是橫向排列的(flex-direction: row),如下上圖藍框部分。
剩下的內容佈局也大致類似,其實就是無限套娃下去。由於偏於原因,這裏就不繼續深入拆解了,大致的佈局思路已經說得很清楚了。
有了 Flex 佈局之後,貌似佈局也變得非常簡單了。但紙上得來終覺淺,還是得自己實際動手練練才知道容易不容易,不然就變成紙上談兵了!
總結
看到這裏,關於 Flex 佈局的核心點就介紹得差不多了。掌握好這幾個核心的知識點,開始去實踐練習基本上沒有什麼太大的問題了。剩下的一些比較小衆的屬性,等用到的時候再去查查看就足夠了。
接下來更多的時間,就是找多幾個實戰案例實踐,唯有實踐才能鞏固所學知識點。後面有機會,我將分享我在 Flex 佈局方面的項目實踐。
如果這篇文章對你有幫助,記得一鍵三連支持我!