深入理解Flex佈局 -- flex-grow & flex-shrink & flex-basis

  • 一、前言

最近在項目裏遇到了一個 Flex 佈局的問題,才發現自己對它的理解還是停留在淺顯的水平,遇到一些特殊情況就不知道如何處理。於是找了些資料深入學習一下,然後將我的學習心得總結成這篇文章。

  • 二、問題還原

先講講我遇到的問題。我希望實現一個左中右三列的佈局,其中左右部分固定寬度,中間部分自適應:
clipboard.png

實現起來很簡單,代碼如下:

<div class="container">
  <div class="left">left</div>
  <div class="middle">
    middle
  </div>
  <div class="right">right</div>
</div>

.container {
  display: flex;
  width: auto;
  height: 300px;
  background: grey;
}

.left {
  flex-basis: 200px;
  background: linear-gradient(to bottom right, green, white);
}

.middle {
  flex: 1;
  background: linear-gradient(to bottom right, yellow, white);
}

.right {
  flex-basis: 300px;
  background: linear-gradient(to bottom right, purple, white);
}

到此爲止一切都很美好。但遇到中間部分內容很長的時候,UI 就變形了:
clipboard.png

爲了固定住左右部分的寬度,需要給 left 和 right 加上flex-shrink: 0。但加上後容器的寬度就被撐開了,頁面底部出現了滾動條:
clipboard.png

而我期望的效果是滾動條出現在中間部分,整個頁面不能滾動。解決方法是給 middle 加上overflow: scroll
clipboard.png

此時的完整代碼如下:

<div class="container">
  <div class="left">left</div>
  <div class="middle">
    middle
    <!-- 寬度爲800px的內容-->
    <div class="long">long</div>
  </div>
  <div class="right">right</div>
</div>

.container {
  display: flex;
  width: auto;
  height: 300px;
  background: grey;
}

.left {
  flex-basis: 200px;
  flex-shrink: 0;
  background: linear-gradient(to bottom right, green, white);
}

.middle {
  flex: 1;
  overflow: scroll;
  background: linear-gradient(to bottom right, yellow, white);
}

.right {
  flex-basis: 300px;
  flex-shrink: 0;
  background: linear-gradient(to bottom right, purple, white);
}

.long {
  width: 800px;
}

完整的 codepen這裏

實戰經驗到此結束,下面我們再深入學習涉及到的知識點。

  • 三、知識點

先來講講上面用到的屬性flex: 1。它其實是一個縮寫,等價於flex: 1 1 0,也就是

flex-grow : 1;
flex-shrink : 1;
flex-basis : 0;
  • flex-grow 表示當有剩餘空間的時候,分配給項目的比例
  • flex-shrink 表示空間不足的時候,項目縮小的比例
  • flex-basis 表示分配空間之前,項目佔據主軸的空間

下面來講講 flex 空間分配的步驟。

  • flex-grow(默認值 0)

假設有一個寬度爲 800 的容器,裏面有 3 個項目,寬度分別是 100,200,300:

<div class="container">
  <div class="left">left</div>
  <div class="middle">middle</div>
  <div class="right">right</div>
</div>

.container {
  display: flex;
  width: 800px;
  height: 300px;
  background: grey;
}

.left {
  flex-basis: 100px;
  background: linear-gradient(to bottom right, green, white);
}

.middle {
  flex-basis: 200px;
  background: linear-gradient(to bottom right, yellow, white);
}

.right {
  flex-basis: 300px;
  background: linear-gradient(to bottom right, purple, white);
}

效果如下:
clipboard.png

這時候就出現了多餘的 200 的空間(灰色部分)。這時候如果我們對左中右分別設置flex-grow爲 2,1,1,各個項目的計算邏輯如下:

  1. 首先將多餘空間 200 除以 4(2 + 1 + 1),等於 50
  2. left = 100 + 2 x 50 = 200
  3. middle = 200 + 1 x 50 = 250
  4. right = 300 + 1 x 50 = 350

clipboard.png

  • flex-shrink(默認值 1)

假設父容器寬度調整爲 550,裏面依然是 3 個項目,寬度分別是 100,200,300,這時候空間就不夠用溢出了。首先要理解清楚,當我們定義一個固定寬度容器爲flex的時候,flex會盡其所能不去改變容器的寬度,而是壓縮項目的寬度。這時我們對左中右分別設置flex-shrink爲 1,2,3,計算邏輯如下:

  1. 溢出空間 = 100 + 200 + 300 - 550 = 50
  2. 總權重 = 1 x 100 + 2 x 200 + 3 x 300 = 1400
  3. left = 100 - (50 x 1 x 100 / 1400) = 96.42
  4. middle = 200 - (50 x 2 x 200 / 1400) = 185.72
  5. right = 300 - (50 x 3 x 300 / 1400) = 267.86

clipboard.png

如果我們不想項目被壓縮,就必須將flex-shrink設爲 0。還是用上面的例子,當左中右的flex-shrink都爲 0 的時候,就會衝破寬度限制,container的寬度將會從 550 變爲 600。
clipboard.png

codepen這裏

  • flex-basis(默認值 auto)

flex-basis指定項目佔據主軸的空間,如果不設置,則等於內容本身的空間:
clipboard.png

  • 四、總結

本文從問題出發,講解了Flex佈局在實戰中的應用,並深入到flex-growflex-shrinkflex-basis的細節,描述了項目空間在填充和溢出情況下的計算方式,希望對你有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章