1. Flex佈局
Flex 是 Flexible Box 的縮寫,意為"彈性佈局",用來為盒狀模型提供最大的靈活性 flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為 0 1 auto
任何一個容器都可以用 Flex 進行佈局(如果不會 flex 佈局的可見阮老師的 Flex 佈局教程),而且 Flex 是發生在父容器和子容器之間的佈局關係的,那麼父容器與子容器的關係是怎麼樣子的,又是怎麼計運算元容器所佔用的空間的呢,怎麼進行彈性佈局的呢?
欲要解決上面的問題,首先得了解 flex-grow 和 flex-shrink 是怎麼計算的?flex-basis 和 width 又有什麼關係和區別?
接下來,我們先提出兩個概念:剩餘空間和溢位空間,具體是什麼意思我們後面慢慢解釋。
2. flex-grow
flex-grow屬性在MDN上的定義是:
定義彈性盒子項(flex-item)的拉伸因子,預設值0”
傳統的佈局是子容器在父容器中從左到右進行佈局,應用 flex 進行佈局,那麼父容器一定設定 display: flex
,子容器要“佔有”並且“瓜分”父容器的空間,如何佔有、瓜分的策略就是彈性佈局的策略。這裡就要解釋到“剩餘空間”的概念:
子容器在父容器的“主軸”上還有多少空間可以“瓜分”,這個可以被“瓜分”的空間就叫做剩餘空間。
文字總是很抽象,舉個例子就能理解剩餘空間了,現在有如下的程式碼:
HTML 程式碼:
<div class="container">
<div class="item a">
<p>A</p>
<p> width:100</p>
</div>
<div class="item b">
<p>B</p>
<p> width:150</p>
</div>
<div class="item c">
<p>C</p>
<p> width:100</p>
</div>
</div>
複製程式碼
CSS程式碼:
.container {
margin:10px;
display: flex;
width: 500px;
height: 200px;
background-color: #eee;
color: #666;
text-align: center;
}
.item {
height: 100px;
}
.item p {
margin: 0;
}
.a{
width: 100px;
background-color:#ff4466;
}
.b{
width: 150px;
background-color:#42b983;
}
.c{
width: 100px;
background-color:#61dafb;
}
複製程式碼
展示的效果如下(最後那個框是截圖的時候的標註,不是展示出來的效果):
一圖勝千言,看到這個圖應該就明白什麼是剩餘空間了。
父容器的主軸還有這麼多剩餘空間,子容器有什麼辦法將這些剩餘空間瓜分來實現彈性的效果呢?
這就需要用到flex-grow
屬性了,flex-grow
定義子容器的瓜分剩餘空間的比例,預設為 0
,即如果存在剩餘空間,也不會去瓜分。
flex-grow
例子,將上面的例子改成如下程式碼:
HTML 程式碼(程式碼只增加了 flex-grow 的說明,沒有其他結構的變動):
<div class="container">
<div class="item a">
<p>A</p>
<p> width:100</p>
<p>flex-grow:1</p>
</div>
<div class="item b">
<p>B</p>
<p> width:150</p>
<p>flex-grow:2</p>
</div>
<div class="item c">
<p>C</p>
<p> width:100</p>
<p>flex-grow:3</p>
</div>
</div>
複製程式碼
CSS 程式碼(給每個子容器增加了 flex-grow):
.container {
margin:10px;
display: flex;
width: 500px;
height: 200px;
background-color: #eee;
color: #666;
text-align: center;
}
.item {
height: 100px;
p {
margin: 0;
}
}
.a{
width: 100px;
flex-grow:1;
background-color:#ff4466;
}
.b{
width: 150px;
flex-grow:2;
background-color:#42b983;
}
.c{
width: 100px;
flex-grow:3;
background-color:#61dafb;
}
複製程式碼
結果如下:
最初,我們發現,子容器的寬度總和只有 350px,父容器寬度為 500px,那麼剩餘空間就出現了,為 150px。當設定了 flex-grow
之後, A,B,C三個子容器會根據自身的 flex-grow
去“瓜分”剩餘空間。
在這裡我們總結為 flex-grow 屬性決定了子容器要佔用父容器多少剩餘空間。
計算方式如下:
- 剩餘空間:x
- 假設有三個flex item元素,flex-grow 的值分別為a, b, c
- 每個元素可以分配的剩餘空間為: a/(a+b+c) * x,b/(a+b+c) * x,c/(a+b+c) * x
以 A 為例子進行說明: A 佔比剩餘空間:1/(1+2+3) = 1/6,那麼 A “瓜分”到的 150*1/6=25
,實際寬度為100+25=125
。
考慮是否可以把 flex-grow 設定的值小於 1,而且 flex-grow 的和也小於 1 呢?只要把上面公式的分母(flex-grow 的和)設定為 1 就好啦!
3. flex-shrink
說完 flex-grow,我們知道了子容器設定了 flex-grow 有可能會被拉伸。那麼什麼情況下子容器被壓縮呢?考慮一種情況:如果子容器寬度超過父容器寬度,即使是設定了 flex-grow,但是由於沒有剩餘空間,就分配不到剩餘空間了。這時候有兩個辦法:換行和壓縮。由於 flex 預設不換行,那麼壓縮的話,怎麼壓縮呢,壓縮多少?此時就需要用到 flex-shrink 屬性了。
flex-shrink屬性在MDN上的定義是:
指定了 flex 元素的收縮規則,預設值是 1
此時,剩餘空間的概念就轉化成了“溢位空間”
計算方式:
- 三個flex item元素的width: w1, w2, w3
- 三個flex item元素的flex-shrink:a, b, c
- 計算總壓縮權重: sum = a * w1 + b * w2 + c * w3
- 計算每個元素壓縮率: S1 = a * w1 / sum,S2 =b * w2 / sum,S3 =c * w3 / sum
- 計算每個元素寬度:width - 壓縮率 * 溢位空間
舉例說明:
<div class="container">
<div class="item a">
<p>A</p>
<p> width:300</p>
<p>flex-shrink: 1</p>
</div>
<div class="item b">
<p>B</p>
<p> width:150</p>
<p>flex-shrink: 2</p>
</div>
<div class="item c">
<p>C</p>
<p> width:200</p>
<p>flex-shrink: 3</p>
</div>
</div>
複製程式碼
.container {
margin:10px;
display: flex;
width: 500px;
height: 200px;
background-color: #eee;
color: #666;
text-align:center;
}
.item {
height: 100px;
}
.item p {
margin: 0;
}
.a{
width: 300px;
flex-grow: 1;
flex-shrink: 1;
background-color:#ff4466;
}
.b{
width: 150px;
flex-shrink: 2;
background-color:#42b983;
}
.c{
width: 200px;
flex-shrink: 3;
background-color:#61dafb;
}
複製程式碼
子容器寬度總和為650,溢位空間為150 總壓縮:300 * 1 + 150 * 2 + 200 * 3 = 1200 A的壓縮率:300*1 / 1200 = 0.25 A的壓縮值:150 * 0.25 = 37.5 A的實際寬度:300 - 37.5 = 262.5
結果如下:
同樣,如果出現flex-shrink總和小於1?那麼計算溢位空間(收縮總和)的結果有所變化。比如:shrink設定為0.1, 0.2, 0.3, 原溢位空間為200,實際溢位空間:200 * (0.1 + 0.2 + 0.3)/ 1 = 120。
注意:如果子容器沒有超出父容器,設定 flex-shrink 無效
4. flex-basis
MDN定義:指定了 flex 元素在主軸方向上的初始大小
一旦 flex item 放進 flex 容器,並不能保證能夠按照 flex-basis 設定的大小展示。瀏覽器會根據 flex-basis 計算主軸是否有剩餘空間。既然是跟寬度相關,那麼 max-width,min-width,width 和 box 的大小優先順序是怎麼樣的。
舉例說明:
<div class="container">
<div class="item a">A</div>
<div class="item b">B</div>
<div class="item c">C</div>
</div>
複製程式碼
.container {
margin:10px;
display: flex;
width: 500px;
height: 200px;
background-color: #eee;
text-align: center;
line-height: 100px;
color: #666;
}
.item {
width: 100px;
height: 100px;
}
.a{
flex-basis: 200px;
background-color:#ff4466;
}
.b{
max-width: 50px;
flex-basis: 150px;
background-color:#42b983;
}
.c{
background-color:#61dafb;
}
複製程式碼
結果如下:
上面的例子可以通過最終元素的寬度看出幾個屬性的優先順序關係:max-width/min-width > flex-basis > width > box
5. 應用場景
- 一種很常見的佈局:當內容區域高度不夠的時候,footer仍然需要固定在底部。這時候,我們可以給main使用flex-grow: 1,使它自動填滿剩餘空間。
2 . 在我們開發一種常見的表單元件的時候,使用flex佈局,可以使輸入框佔滿剩餘空間。
而大部分場景下我們不希望元素被壓縮,所以flex-shrink通常設定為0。
6. 總結
最後,我們需要注意的是:
- flex items 總和超出 flex 容器,會根據 flex-shrink 的設定進行壓縮
- 如果有剩餘空間,如果設定 flex-grow,子容器的實際寬度跟 flex-grow 的設定相關。如果沒有設定flex-grow,則按照 flex-basis 展示實際寬度
參考文獻: