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