Flex 佈局目前已經非常流行了,現在幾乎已經相容所有瀏覽器了。在文章開始之前我們需要思考一個問題:我們為什麼要使用 Flex 佈局?
其實答案很簡單,那就是 Flex 佈局好用。一個新事物的出現往往是因為舊事物不那麼好用了,比如,如果想讓你用傳統的 css 佈局來實現一個塊元素垂直水平居中你會怎麼做?實現水平居中很簡單,margin: 0 auto
就行,而實現垂直水平居中則可以使用定位實現:
<div class="container">
<div class="item"></div>
</div>
.container {
position: relative;
width: 300px;
height: 300px;
background: red;
}
.item {
position: absolute;
background: black;
width: 50px;
height: 50px;
margin: auto;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
或者
.item {
position: absolute;
background: black;
width: 50px;
height: 50px;
margin: auto;
left: calc(50% - 25px);
top: calc(50% - 25px);
}
但是這樣都顯得特別繁瑣,明明可以一個屬性就能解決的事情沒必要寫這麼麻煩。而使用 Flex 則可以使用 place-content 屬性簡單的實現(place-content 為 justify-content 和 align-content 簡寫屬性)
.container {
width: 300px;
height: 300px;
background: red;
display: flex;
place-content: center;
}
.item {
background: black;
width: 50px;
height: 50px;
}
接下來的本篇文章將會帶領大家一起來探討Flex
佈局
基本概念
我們先寫一段程式碼作為示例(部分屬性省略)
html
<div class="container">
<div class="item">flex專案</div>
<div class="item">flex專案</div>
<div class="item">flex專案</div>
<div class="item">flex專案</div>
</div>
.container {
display: flex;
width: 800px;
gap: 10px;
}
.item {
color: #fff;
}
flex 容器
我們可以將一個元素的 display 屬性設定為 flex,此時這個元素則成為flex 容器比如container
元素
flex 專案
flex 容器的子元素稱為flex 專案,比如item
元素
軸
flex 佈局有兩個軸,主軸和交叉軸,至於哪個是主軸哪個是交叉軸則有flex 容器的flex-direction
屬性決定,預設為:flex-direction:row
,既橫向為主軸,縱向為交叉軸,
flex-direction
還可以設定其它三個屬性,分別為row-reverse
,column
,column-reverse
。
- row-reverse
- column
- column-reverse
從這裡我們可以看出 Flex 軸的方向不是固定不變的,它受到flex-direction
的影響
不足空間和剩餘空間
當 Flex 專案總寬度小於 Flex 容器寬度時就會出現剩餘空間
當 Flex 專案總寬度大於 Flex 容器寬度時就會出現不足空間
Flex 專案之間的間距
Flex 專案之間的間距可以直接在 Flex 容器上設定 gap 屬性即可,如
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
</div>
.container {
display: flex;
width: 500px;
height: 400px;
gap: 10px;
}
.item {
width: 150px;
height: 40px;
}
Flex 屬性
flex
屬性是flex-grow
,flex-shrink
,flex-basis
三個屬性的簡寫。下面我們來看下它們分別是什麼。
-
flex-basis
可以設定 Flex 專案的大小,一般主軸為水平方向的話和 width 解析方式相同,但是它不一定是 Flex 專案最終大小,Flex 專案最終大小受到flex-grow
,flex-shrink
以及剩餘空間等影響,後面文章會告訴大家最終大小的計算方式 -
flex-grow
為 Flex 專案的擴充套件係數,當 Flex 專案總和小於 Flex 容器時就會出現剩餘空間,而flex-grow
的值則可以決定這個 Flex 專案可以分到多少剩餘空間 -
flex-shrink
為 Flex 專案的收縮係數,同樣的,當 Flex 專案總和大於 Flex 容器時就會出現不足空間,flex-shrink
的值則可以決定這個 Flex 專案需要減去多少不足空間
既然flex
屬性是這三個屬性的簡寫,那麼flex
屬性簡寫方式分別代表什麼呢?
flex
屬性可以為 1 個值,2 個值,3 個值,接下來我們就分別來看看它們代表什麼意思
- 一個值
如果flex
屬性只有一個值的話,我們可以看這個值是否帶單位,帶單位那就是flex-basis
,不帶就是flex-grow
.item {
flex: 1;
/* 相當於 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
.item {
flex: 30px;
/* 相當於 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 30px;
}
- 兩個值
當flex
屬性有兩個值的話,第一個無單位的值就是flex-grow
,第一個無單位的值則是flex-shrink
,有單位的就是flex-basis
.item {
flex: 1 2;
/* 相當於 */
flex-grow: 1;
flex-shrink: 2;
flex-basis: 0;
}
.item {
flex: 30px 2;
/* 相當於 */
flex-grow: 2;
flex-shrink: 1;
flex-basis: 30px;
}
- 三個值
當flex
屬性有三個值的話,第一個無單位的值就是flex-grow
,第一個無單位的值則是flex-shrink
,有單位的就是flex-basis
.item {
flex: 1 2 10px;
/* 相當於 */
flex-grow: 1;
flex-shrink: 2;
flex-basis: 10px;
}
.item {
flex: 30px 2 1;
/* 相當於 */
flex-grow: 2;
flex-shrink: 1;
flex-basis: 30px;
}
.item {
flex: 2 30px 1;
/* 相當於 */
flex-grow: 2;
flex-shrink: 1;
flex-basis: 30px;
}
另外,flex 的值還可以為initial
,auto
,none
。
- initial
initial 為預設值,和不設定 flex 屬性的時候表現一樣,既 Flex 專案不會擴充套件,但會收縮,Flex 專案大小有本身內容決定
.item {
flex: initial;
/* 相當於 */
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
- auto
當 flex 設定為 auto 時,Flex 專案會根據自身內容確定flex-basis
,既會擴充也會收縮
.item {
flex: auto;
/* 相當於 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
}
- none
none 表示 Flex 專案既不收縮,也不會擴充套件
.item {
flex: none;
/* 相當於 */
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
}
Flex 專案大小的計算
首先看一下 flex-grow 的計算方式
flex-grow
面試中經常問到: 為什麼 flex 設定為 1 的時候,Flex 專案就會均分 Flex 容器? 其實 Flex 專案設定為 1 不一定會均分容器(後面會解釋),這裡我們先看下均分的情況是如何發生的
同樣的我們先舉個例子
<div class="container">
<div class="item">Xiaoyue</div>
<div class="item">June</div>
<div class="item">Alice</div>
<div class="item">Youhu</div>
<div class="item">Liehuhu</div>
</div>
.container {
display: flex;
width: 800px;
}
.item {
flex: 1;
font-size: 30px;
}
flex 容器總寬度為 800px,flex 專案設定為flex:1
,此時頁面上顯示
我們可以看到每個專案的寬度為 800/5=160,下面來解釋一下為什麼會均分:
首先
.item {
flex: 1;
/* 相當於 */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
因為flex-basis
為 0,所有 Flex 專案擴充套件係數都是 1,所以它們分到的剩餘空間都是一樣的。下面看一下是如何計算出最終專案大小的
這裡先給出一個公式:
Flex專案彈性量 = (Flex容器剩餘空間/所有flex-grow總和)*當前Flex專案的flex-grow
其中Flex專案彈性量
指的是分配給 Flex 專案多少的剩餘空間,所以 Flex 專案的最終寬度為
flex-basis+Flex專案彈性量
。
根據這個公式,上面的均分也就很好理解了,因為所有的flex-basis
為 0,所以剩餘空間就是 800px,每個 Flex 專案的彈性量也就是(800/1+1+1+1+1)*1=160
,那麼最終寬度也就是160+0=160
剛剛說過 flex 設定為 1 時 Flex 專案並不一定會被均分,下面就來介紹一下這種情況,我們修改一下示例中的 html,將第一個 item 中換成一個長單詞
<div class="container">
<div class="item">Xiaoyueyueyue</div>
<div class="item">June</div>
<div class="item">Alice</div>
<div class="item">Youhu</div>
<div class="item">Liehu</div>
</div>
此時會發現 Flex 容器並沒有被均分
因為計算出的靈活性 200px 小於第一個 Flex 專案的min-content
(217.16px),此時瀏覽器會採用 Flex 專案的min-content
作為最終寬度,而後面的 Flex 專案會在第一個 Flex 專案計算完畢後再進行同樣的計算
我們修改一下 flex,給它設定一個 flex-basis,看下它計算之後的情況
.item {
text-align: center;
flex: 1 100px;
}
因為每個專案的flex-basis
都是 100px,Flex 容器剩餘空間為800-500=300px
,所以彈性量就是(300/5)*1=60px
,最終寬度理論應該為100+60=160px
,同樣的因為第一個 Flex 專案的min-content
為 217.16px,所以第一個 Flex 專案寬度被設定為 217.16px,最終表現和上面一樣
我們再來看一下為什麼第 2,3,4,5 個 Flex 專案寬度為什麼是 145.71px
當瀏覽器計算完第一個 Flex 專案為 217.16px 後,此時的剩餘空間為800-217.16-100*4=182.84
,第 2 個 Flex 專案彈性量為(182.84/1+1+1+1)*1=45.71
,所以最終寬度為100+45.71=145.71px
,同樣的後面的 Flex 專案計算方式是一樣的,但是如果後面再遇到長單詞,假如第五個是長單詞,那麼不足空間將會發生變化,瀏覽器會將第五個 Flex 專案寬度計算完畢後再回頭進行一輪計算,具體情況這裡不再展開
所以說想要均分 Flex 容器 flex 設定為 1 並不能用在所有場景中,其實當 Flex 專案中有固定寬度元素也會出現這種情況,比如一張圖片等,當然如果你想要解決這個問題其實也很簡單,將 Flex 專案的min-width
設定為 0 即可
.item {
flex: 1 100px;
min-width: 0;
}
flex-grow 為小數
flex-grow 的值不僅可以為正整數,還可以為小數,當為小數時也分為兩種情況:所有 Flex 專案的 flex-grow 之和小於等於 1 和大於 1,我們先看小於等於 1 的情況,將例子的改成
<div class="container">
<div class="item">Acc</div>
<div class="item">Bc</div>
<div class="item">C</div>
<div class="item">DDD</div>
<div class="item">E</div>
</div>
.item:nth-of-type(1) {
flex-grow: 0.1;
}
.item:nth-of-type(2) {
flex-grow: 0.2;
}
.item:nth-of-type(3) {
flex-grow: 0.2;
}
.item:nth-of-type(4) {
flex-grow: 0.1;
}
.item:nth-of-type(5) {
flex-grow: 0.1;
}
效果如圖
我們可以發現專案並沒有佔滿容器,它的每個專案的彈性量計算方式為
Flex專案彈性量=Flex容器剩餘空間*當前Flex專案的flex-grow
相應的每個專案的實際寬度也就是flex-basis+彈性量
,首先先不設定 flex-grow,我們可以看到每個專案的 flex-basis 分別為: 51.2 , 33.88 , 20.08 , 68.56 , 16.5
所以我們可以計算出 Flex 容器的剩餘空間為800-51.2 -33.88 - 20.08 - 68.56 - 16.5=609.78
,這樣我們就可以算出每個專案的實際尺寸為
A: 實際寬度 = 51.2 + 609.78*0.1 = 112.178
B: 實際寬度 = 33.88 + 609.78*0.2 = 155.836
...
下面看下 flex-grow 之和大於 1 的情況,將例子中的 css 改為
.item:nth-of-type(1) {
flex-grow: 0.1;
}
.item:nth-of-type(2) {
flex-grow: 0.2;
}
.item:nth-of-type(3) {
flex-grow: 0.3;
}
.item:nth-of-type(4) {
flex-grow: 0.4;
}
.item:nth-of-type(5) {
flex-grow: 0.5;
}
此時的效果為
可以看出 Flex 專案是佔滿容器的,它的計算方式其實和 flex-grow 為正整數時一樣
Flex專案彈性量 = (Flex容器剩餘空間/所有flex-grow總和)*當前Flex專案的flex-grow
所以我們可以得出一個結論: Flex 專案的 flex-grow 之和小於 1,Flex 專案不會佔滿 Flex 容器
flex-shrink
flex-shrink 其實和 flex-grow 基本一樣,就是擴充套件變成了收縮,flex-grow 是專案比例增加容器剩餘空間,而 flex-shrink 則是比例減去容器不足空間
修改一下我們的例子:
.item {
flex-basis: 200px;
/* 相當於 */
flex-shrink: 1;
flex-grow: 0;
flex-basis: 200px;
}
此時專案的總寬度200*5=1000px
已經大於容器總寬度800px
,此時計算第一個專案的不足空間就是800-200*5=-200px
,第二個專案的不足空間則是800-第一個專案實際寬度-200*4
,依次類推
最終計算公式其實和 flex-grow 計算差不多
Flex專案彈性量 = (Flex容器不足空間/所有flex-shrink總和)*當前Flex專案的flex-shrink
只不過,所以上面例子每個專案可以計算出實際寬度為
第一個 Flex 專案: 200+((800-200x5)/5)*1 = 160px
第二個 Flex 專案: 200+((800-160-200x4)/4)*1 = 160px
第三個 Flex 專案: 200+((800-160-160-200x3)/3)*1 = 160px
第四個 Flex 專案: 200+((800-160-160-160-200x2)/2)*1 = 160px
第五個 Flex 專案: 200+((800-160-160-160-160-200x1)/1)*1 = 160px
如果 Flex 專案的min-content
大於flex-basis
,那麼最終的實際寬度將會取該專案的min-content
,比如改一下例子,將第一個 Flex 專案改成長單詞
<div class="container">
<div class="item">XiaoyueXiaoyue</div>
<div class="item">June</div>
<div class="item">Alice</div>
<div class="item">Youhu</div>
<div class="item">Liehu</div>
</div>
可以看出瀏覽器最終採用的是第一個 Flex 專案的min-content
作為實際寬度,相應的後面 Flex 專案的寬度會等前一個 Flex 專案計算完畢後在進行計算
比如第二個 Flex 專案寬度= 200+((800-228.75-200x4)/4)*1 = 142.81px
flex-shrink 為小數
同樣的 flex-shrink 也會出現小數的情況,也分為 Flex 專案的 flex-shrink 之和小於等於 1 和大於 1 兩種情況,如果大於 1 和上面的計算方式一樣,所以我們只看小於 1 的情況,將我們的例子改為
.item {
flex-basis: 200px;
flex-shrink: 0.1;
}
效果為
此時我們會發現 Flex 專案溢位了容器,所以我們便可以得出一個結論:Flex 專案的 flex-shrink 之和小於 1,Flex 專案會溢位 Flex 容器
下面看一下它的計算公式
Flex專案彈性量=Flex容器不足空間*當前Flex專案的flex-shrink
Flex專案實際寬度=flex-basis + Flex專案彈性量
比如上面例子的每個 Flex 專案計算結果為
第一個 Flex 專案寬度 = 200+(800-200x5)x0.1=180px
,但是由於它本身的min-content
為 228.75,所以最終寬度為 228.75
第二個 Flex 專案寬度 =200-(800-228.75-200x4)x0.1=117.125
第三個 Flex 專案寬度...
Flex 的對齊方式
Flex 中關於對齊方式的屬性有很多,其主要分為兩種,一是主軸對齊方式:justify-*,二是交叉軸對齊方式:align-*
首先改一下我們的例子,將容器設定為寬高為 500x400 的容器(部分屬性省略)
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>
.container {
display: flex;
width: 500px;
height: 400px;
}
.item {
width: 100px;
height: 40px;
}
主軸對齊屬性
這裡以橫向為主軸,縱向為交叉軸
justify-content
justify-content的值可以為:
- flex-start 預設值,主軸起點對齊
- flex-end 主軸終點對齊
- left 預設情況下和 flex-start 一致
- right 預設情況下和 flex-end 一致
- center 主軸居中對齊
- space-between 主軸兩端對齊,並且 Flex 專案間距相等
- space-around 專案左右周圍空間相等
- space-evenly 任何兩個專案之間的間距以及邊緣的空間相等
交叉軸對齊方式
align-content
align-content 屬性控制整個 Flex 專案在 Flex 容器中交叉軸的對齊方式
**注意設定 align-content 屬性時候必須將 flex-wrap 設定成 wrap 或者 wrap-reverse。**它可以取得值為
- stretch 預設值,當我們 Flex 元素不設定高度的時候,預設是拉伸的
比如將 Flex 元素寬度去掉
.item {
width: 100px;
}
- flex-start 位於容器開頭,這個和 flex-direction:屬性有關,預設在頂部
- flex-end 位於容器結尾
- center 元素居中對齊
- space-between 交叉軸上下對齊,並且 Flex 專案上下間距相等
此時我們改下例子中 Flex 專案的寬度使其換行,因為如果 Flex 專案只有一行,那麼 space-between 與 flex-start 表現一致
.item {
width: 300px;
}
- space-around 專案上下週圍空間相等
- space-evenly 任何兩個專案之間的上下間距以及邊緣的空間相等
align-items
align-items 屬性定義 flex 子項在 flex 容器的當前行的交叉軸方向上的對齊方式。它與 align-content 有相似的地方,它的取值有
-
stretch 預設值,當我們 Flex 元素不設定高度的時候,預設是拉伸的
-
center 元素位於容器的中心,每個當前行在圖中已經框起來
-
flex-start 位於容器開頭
-
flex-end 位於容器結尾
-
baseline 位於容器的基線上
比如給 A 專案一個 padding-top
.item:nth-of-type(1) {
padding-top: 50px;
}
沒設定 baseline 的表現
設定 baseline 之後
透過上面的例子我們可以發現,如果想要整個 Flex 專案垂直對齊,在只有一行的情況下,align-items 和 align-content 設定為 center 都可以做到,但是如果出現多行的情況下 align-items 就不再適用了
align-self
上面都是給 Flex 容器設定的屬性,但是如果想要控制單個 Flex 專案的對齊方式該怎麼辦呢?
其實 Flex 佈局中已經考慮到了這個問題,於是就有個 align-self 屬性來控制單個 Flex 專案在 Flex 容器側交叉軸的對齊方式。
align-self 和 align-items 屬性值幾乎是一致的,比如我們將整個 Flex 專案設定為 center,第二個 Flex 專案設定為 flex-start
.container {
display: flex;
width: 500px;
height: 400px;
align-items: center;
}
.item {
width: 100px;
height: 40px;
}
.item:nth-of-type(2) {
align-self: flex-start;
}
注意,除了以上提到的屬性的屬性值,還可以設定為 CSS 的關鍵詞如 inherit 、initial 等
交叉軸與主軸簡寫
place-content
place-content
為 justify-content
和 align-content
的簡寫形式,可以取一個值和兩個值,如果設定一個值那麼 justify-content
和 align-content
都為這個值,如果是兩個值,第一個值為 align-content
,第二個則是 justify-content
到這裡關於Flex佈局基本已經介紹完了,肯定會有些細枝末節沒有考慮到,這可能就需要我們在平時工作和學習中去發現了
點個贊吧~