你真的理解 flex 屬性嗎,最詳細 flex 屬性計算方法就在這

引言

最近想更改一下博客首頁的佈局樣式,添加幾個側欄,就去看了看常見的佈局方式,什麼「雙飛翼佈局」「聖盃佈局」也就兩側固定中間自適應的三欄佈局方案。不過我以前一直都是用的 Flex 佈局,Flex 佈局是否是也能夠作到呢,網上搜索一番,代碼以下:css

<html lang="en">
  <body>
    <div style="display: flex;">
      <div class="a"></div>
      <div class="b"></div>
      <div class="c"></div>
    </div>
  </body>

  <style> .a { background-color: thistle; width: 20%; } .b { background-color: tomato; flex: 1; } .c { background-color: violet; width: 100px; } .a, .b, .c { height: 100px; } </style>
</html>
複製代碼

這樣一看是否是很是簡單,比前文介紹的兩種佈局優雅多了,可是讓我困惑的是第 17 行的 flex: 1,在阮一峯老師的博客上是這樣描述的html

flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,默認值爲0 1 auto。wordpress

Google 搜索出來的結果也都是說 flex 屬性就是簡寫,那爲何 flex:1能夠實現中間部分自適應,這黑箱通常的原理一直困擾着我,flex 究竟是怎麼起做用的呢,下面咱們來詳細研究研究。(關於這幾個屬性的意義能夠看阮一峯老師的博文)) 佈局

flex 屬性的語法

首當其衝的困惑就是 flex屬性是flex-growflex-shrinkflex-basis的縮寫。那麼爲何會有flex:1這種後面接一個數字的呢?這就不得不提到 flex 的語法,不知道同窗們有沒有看 CSS 語法的習慣,查詢 MDN 可知其正式語法爲flex

none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]ui

感受看起來眼都花了,這怎麼理解嘛,別急咱們一個一個來分析,|這個符號表示排他,能夠爲後者或者前者,因此這就有兩種語法了this

flex: none;
flex: [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
複製代碼

接下來就是方括號[],表示範圍,也就是說 flex 屬性後面跟隨的以三個數就是表示這三個屬性的,好比:flexbox

{
  flex:1 1 100px
}
/* 等於 */
{
  flex-grow:1
  flex-shrink:1
  flex-basis:100px
}
複製代碼

再看符號|| 表示的意思是「或者」,能夠爲 flex: [ <'flex-basis'> ]或者爲flex: [ <'flex-grow'> <'flex-shrink'>] ,也能夠共存。而符號表示 0 或者 1,也就是說flex-shrink無關緊要,這樣一來一共是有如下幾種組合方式。spa

flex: [ <'flex-basis'> ]
flex: [ <'flex-grow'>]
flex: [ <'flex-grow'> <'flex-shrink'>]
flex: [ <'flex-grow'> <'flex-basis'> ]
flex: [ <'flex-grow'> <'flex-shrink'><'flex-basis'> ]
複製代碼

能夠發現 flex 屬性後面跟一個值的狀況就是 1 和 2 行,而 flex-basis 的單位是長度單位,因此flex:1 就至關於 flex-grow : 1,原來如此,這樣設置就使元素填滿剩餘空間。從完成「雙飛翼佈局」角度來講這個疑問好像已經獲得瞭解答,可是 flex 屬性的這三個值卻遠遠沒有這麼簡單。
3d

深刻 flex 屬性值

簡單介紹一下這三個屬性

  • flex-grow
    • 指定了容器剩餘空間多餘時候的分配規則,默認值是0,多餘空間不分配。
  • flex-shrink
    • 指定了容器剩餘空間不足時候的分配規則,默認值是1,空間不足要分配。
  • flex-basis
    • 指定了固定的分配數量,默認值是auto。如會忽略設置的同時設置width或者height屬性。

flex-grow 計算規則

對於單個元素來講

  • 0 = flex-grow
    • 如有剩餘空間不進行分配,也就是長度不會變化,width 設置多寬就是多寬,這也是默認狀態
  • 1 >= flex-grow
    • 有剩餘空間就分配,在只有一個元素的狀況下,效果就是元素佔滿
  • 0 < flex-grow < 1
    • 這種狀況比較少見,元素分配空間爲可分配空間的 flex-grow / 1,看一下實例比較直觀

演示代碼以下:

<html>
  <body>
    <div class="flex">
      <div class="a"></div>
    </div>
  </body>
  <style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-grow: 0.1; height: 100px; } </style>
</html>

複製代碼

元素 a 本來的寬度值爲 100px ,而後手動將 flex 寬度設置爲 500px,這個時候再查看元素 a 的實際寬度,爲 140px

enter description here

enter description here

分配空間(140-100 = 40)=可分配空間(500-100=400px)* flex-grow (0.1)
因此元素實際寬度 = 自身長度(100)+分配空間(40)= 140px

多個元素

也是有三種狀況,爲 0 很容易理解就不介紹了

都大於 1

  • 這個時候剩餘空間按照 flex-grow 的值按比例分配,上代碼
<html lang="en">
  <body>
    <div class="flex">
      <div class="a"></div>
      <div class="b"></div>
      <div class="c"></div>
    </div>
  </body>

  <style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-grow: 1; } .b { background-color: tomato; width: 100px; flex: 2; } .c { background-color: violet; width: 100px; flex: 3; } .a, .b, .c { height: 100px; } </style>
</html>
複製代碼

同樣手動將 flex 元素寬度設置爲 500px,咱們來看一下三個元素的實際寬度

enter description here

enter description here

enter description here

咱們來看看實際寬度是怎麼計算出來的
a 實際寬度 = 可分配空間(500-300=200)* (1 / 1+2+3)+設置寬度(100)= 33.33 + 100 =133.33
其餘幾個也是這樣計算的,應該仍是挺容易理解的吧

當全部元素的 flex-grow 值相加小於 1

  • 這個時候不會將全部可分配空間分配出去,實際分配空間 = 可分配空間 * flex-grow 之和,上代碼瞧瞧
<html lang="en">
  <body>
    <div class="flex">
      <div class="a">a</div>
      <div class="b">b</div>
      <div class="c">c</div>
    </div>
  </body>

  <style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-grow: 0.1; } .b { background-color: tomato; width: 100px; flex-grow: 0.2; } .c { background-color: aqua; width: 100px; flex-grow: 0.3; } .a, .b, .c { height: 100px; } </style>
</html>

複製代碼

enter description here

能夠看到元素們並無佔滿空間, 看看實際寬度

enter description here


a 實際寬度 = 實際分配空間 * (0.1 / 0.1+0.2+0.3)+設置寬度(100)= 20  + 100 =120
和大於 0 狀況相比較的話僅僅是「可分配空間」->「實際分配空間」,而上文提到過

實際分配空間 = 可分配空間 * flex-grow 之和

也就是本實例中的實際分配空間爲 200 * (0.1+0.2+0.3)=120,其實就是把可分配空間與 flex-grow 之和相乘,而後按比例分配空間。

元素 flex-grow 值都小於 0 可是相加大於 1

這種狀況其實想想就能得出結論,和大於 1,就是佔滿可分配空間,而後按照比例分配

元素 flex-grow 有大於 1 有小於 1

其實也是同樣結論,佔滿可分配空間以後,而後按照比例分配

結論

到這咱們就能夠得出結論了,其實這種對單個 flex-grow 值進行分類的方式是錯誤的,而應該按照全部 flex-grow 相加是否大於 1,由於大於 1 就將全部剩餘空間按比例分配,小於 1 則須要先計算實際分配空間再按比例分配,不會佔滿全部剩餘空間。

flex-shrink 計算規則

flex-shrink 屬性是當父元素長度不夠的時候各元素的縮小規則,默認爲 1 ,也就是你們都按照相同比例縮小,至於具體怎麼縮小,是否是也像 flex-grow 那樣按照數值等比例縮小呢,並無那麼簡單,咱們先來看個實例,元素寬度相等的狀況下:

<html lang="en">
  <body>
    <div class="flex">
      <div class="a">a</div>
      <div class="b">b</div>
      <div class="c">c</div>
    </div>
  </body>

  <style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 200px; flex-shrink: 1; } .b { background-color: tomato; width: 200px; flex-shrink: 2; } .c { background-color: aqua; width: 200px; flex-shrink: 3; } .a, .b, .c { height: 100px; } </style>
</html>

複製代碼

手動將 flex 元素寬度設置爲 400px ,這個時候看三個子元素的實際寬度

enter description here

enter description here

enter description here

很容易能夠經過計算得出

元素 c 收縮長度 = 實際長度(200) - 超出長度(600-400)*(3/1+2+3) = 100

此時計算方式確實和 flex-grow 如出一轍,可是當各元素長度不同的時候呢?

<html lang="en">
  <body>
    <div class="flex">
      <div class="a">a</div>
      <div class="b">b</div>
      <div class="c">c</div>
    </div>
  </body>

  <style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-shrink: 1; } .b { background-color: tomato; width: 200px; flex-shrink: 2; } .c { background-color: aqua; width: 300px; flex-shrink: 3; } .a, .b, .c { height: 100px; } </style>
</html>
複製代碼

enter description here

enter description here

enter description here

a 收縮長度 = 14.28
b 收縮長度 = 57.14
c 收縮長度 = 128.58
能夠看到收縮長度並不和元素各自的 flex-shrink 值成正比,查閱 W3 文檔和 MDN 也沒有發現詳細的計算方式,Google 了一大圈終於破解了這個祕密,原來與 flex-grow 延伸長度只與 flex-grow 值相關不同,flex-shrink 元素的收縮長度不只和 flex-shrink 相關,還與元素自身大小相關,具體計算方式以下:

收縮長度 = (元素寬度 * flex-shrink) / (100 * 1+200 * 2+300 * 3) * 須要收縮寬度

代入本例計算一下:
a 元素收縮長度 = 100 * 1/ (100 * 1+200 * 2+300 * 3) * ( 600-400 ) = 14.28 =100 - 85.72
與實際狀況相複合,flex-shrink 瞭解完畢。 等着! 忘了 flex-grow 裏面當 flex-grow 相加小於 1 這種情形了嗎,那麼在這是怎麼表現的呢,看看實例:

<html lang="en">
  <body>
    <div class="flex">
      <div class="a">a</div>
      <div class="b">b</div>
      <div class="c">c</div>
    </div>
  </body>

  <style> .flex { display: flex; background-color: violet; } .a { background-color: thistle; width: 100px; flex-shrink: 0.1; } .b { background-color: tomato; width: 200px; flex-shrink: 0.2; } .c { background-color: aqua; width: 300px; flex-shrink: 0.3; } .a, .b, .c { height: 100px; } </style>
</html>

複製代碼

enter description here

能夠很直觀的看到,三元素長度相加是大於 flex 元素長度的,也就是說並無「徹底」收縮,各個元素長度爲

enter description here

enter description here

enter description here
經過類比 flex-grow 能夠發現:

實際總收縮長度 = 須要收縮長度 * flex-shrink 之和

在本例中,實際收縮長度 = 200 * 0.6 = 120 =600 - 480(收縮後總長度),與實際符合,得出實際收縮長度以後各元素收縮長度就和上文提到的方法是同樣的了。

計算方式總結

雖然上面的計算公式看起來比較複雜,其實理解了以後仍是比較簡單的,借用知乎@謝然的總結:

若是全部元素的 flex-grow/shrink 之和大於等於 1,則全部子元素的尺寸必定會被調整到適應父元素的尺寸(在不考慮 max/min-width/height 的前提下),而若是 flex-grow/shrink 之和小於 1,則只會 grow 或 shrink 全部元素 flex-grow/shrink 之和相對於 1 的比例。grow 時的每一個元素的權重即爲元素的 flex-grow 的值;shrink 時每一個元素的權重則爲元素 flex-shrink 乘以 width 後的值。

總結

說到 flex 佈局,誰還不能說上幾句,彷彿全世界都在用 flex 佈局了,可是你真的瞭解嗎,我其實最先開始接觸 CSS 的時候就是使用的 flex 佈局,垂直居中什麼的玩得特別 6 ,可是在這幾天纔對 flex 屬性有了真正的認識。這也讓我認識到不求甚解在技術界是一種陋習,直接照着寫上一句 flex:1確實很容易實現三欄佈局,可是當需求發生變化就懵逼了。只有真正瞭解了底層原理才能爲所欲爲的實現心中所想。
還有一點就是你的信息來源渠道很大程度上決定了你信息的準確性與真實性,官網文檔永遠是最正確最完善的,儘可能去信息源頭尋找答案。強如阮一峯老師的flex教程中對於 flex 屬性的描述也不夠清楚,Google 永遠都比百度好使。
到這咱們的深刻挖掘就告一段落了,可能你發現不是還有 flex-basis 沒有講嗎,這是由於 flex-basis 也是一個有很是多細節的屬性,可是其細節又與這兩個須要計算的不同,值得單獨寫一篇文章來進行介紹,在下篇文章中咱們再來細聊。

參考文章

相關文章
相關標籤/搜索