深刻理解 flex-grow、flex-shrink、flex-basis

1. Flex佈局

Flex 是 Flexible Box 的縮寫,意爲"彈性佈局",用來爲盒狀模型提供最大的靈活性 flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,默認值爲 0 1 autocss

任何一個容器均可以用 Flex 進行佈局(若是不會 flex 佈局的可見阮老師的 Flex 佈局教程),並且 Flex 是發生在父容器和子容器之間的佈局關係的,那麼父容器與子容器的關係是怎麼樣子的,又是怎麼計算子容器所佔用的空間的呢,怎麼進行彈性佈局的呢?html

欲要解決上面的問題,首先得了解 flex-grow 和 flex-shrink 是怎麼計算的?flex-basis 和 width 又有什麼關係和區別?瀏覽器

接下來,咱們先提出兩個概念:剩餘空間和溢出空間,具體是什麼意思咱們後面慢慢解釋。佈局

2. flex-grow

flex-grow屬性在MDN上的定義是:post

定義彈性盒子項(flex-item)的拉伸因子,默認值0」flex

傳統的佈局是子容器在父容器中從左到右進行佈局,應用 flex 進行佈局,那麼父容器必定設置 display: flex,子容器要「佔有」而且「瓜分」父容器的空間,如何佔有、瓜分的策略就是彈性佈局的策略。這裏就要解釋到「剩餘空間」的概念:spa

子容器在父容器的「主軸」上還有多少空間能夠「瓜分」,這個能夠被「瓜分」的空間就叫作剩餘空間。3d

文字老是很抽象,舉個例子就能理解剩餘空間了,如今有以下的代碼:code

HTML 代碼:cdn

<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;
}
複製代碼

展現的效果以下(最後那個框是截圖的時候的標註,不是展現出來的效果):

image-20191129122900800

一圖勝千言,看到這個圖應該就明白什麼是剩餘空間了。

父容器的主軸還有這麼多剩餘空間,子容器有什麼辦法將這些剩餘空間瓜分來實現彈性的效果呢?

這就須要用到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. 應用場景

  1. 一種很常見的佈局:當內容區域高度不夠的時候,footer仍然須要固定在底部。這時候,咱們能夠給main使用flex-grow: 1,使它自動填滿剩餘空間。

2 . 在咱們開發一種常見的表單組件的時候,使用flex佈局,可使輸入框佔滿剩餘空間。

而大部分場景下咱們不但願元素被壓縮,因此flex-shrink一般設置爲0。

6. 總結

最後,咱們須要注意的是:

  • flex items 總和超出 flex 容器,會根據 flex-shrink 的設置進行壓縮
  • 若是有剩餘空間,若是設置 flex-grow,子容器的實際寬度跟 flex-grow 的設置相關。若是沒有設置flex-grow,則按照 flex-basis 展現實際寬度

參考文獻:

相關文章
相關標籤/搜索