此篇是延續先前的 Flex 的文章(圖解:CSS Flex 屬性一點也不難),本篇則是著重在 flex 中的 flex-grow
、flex-shrink
和 flex-basis
這三個屬性,如果對於 Flex 基礎尚不熟悉的可先閱讀前一篇文章。
首先,回顧下先前的三個屬性介紹:
flex 是縮寫,裡面依序包含三個屬性 flex-grow
、flex-shrink
和 flex-basis
。
- flex-grow: 元件的伸展性,是一個數值,當空間分配還有剩餘時的當前元件的伸展性,預設值為
0
,如果設置為 0 則不會縮放。 - flex-shrink: 元件的收縮性: 元件的伸展性,是一個數值,當空間分配還不足時的當前元件的收縮性,預設值為
0
,如果設置為 0 則不會縮放。 - flex-basis: 元件的基準值,可使用不同的單位值。
在以上的 flex-grow
、flex-shrink
中,這兩個數性可以填入任意整數,關鍵也在於這個任意整數的計算方式如何,本篇將用圖文方式介紹其中運算的規則。
grow, shrink 的計算概念
這兩者所填入的皆是整數,運作的概念上非常接近,都是 按比例分配剩餘空間,只是兩者是在相反的情境下運作,我們先來介紹比較常使用到的 flex-grow
,接下來再用相同的概念來理解 shrink
。
Grow 伸展值,分配剩餘的空間
我們先建立一個簡單的基礎,在一個外部容器上加上 display: flex;
,內部則補上 flex: 1;
預期會得到如下的結果:三個等比切分的內元素(三個寬度各佔 33%)。
下方的介面中,可以自行開啟 HTML, CSS 來檢視、調整原始碼,如果看到的結果不符合預期可以點選右下角的 rerun
。
See the Pen Flex 寬度計算規則 - 1 by Wcc723 (@Wcc723) on CodePen.
接下來,為了讓接下來的實驗更好驗證,對於這些元素再補上一些設定:
- 外層容器設定為 600px
- 內容最左邊的元素設定 200px 寬度(flex-basis 強制設定)
- 右方兩個藍色元素設定 flex-grow: 1
到這個階段會看到以下的結果,三個方框的寬度依然是一致的(都是 200px)。
See the Pen Flex 寬度計算規則 - 2 by Wcc723 (@Wcc723) on CodePen.
接下來,將最右方的元素 flex-grow 改為 2,則可以看到以下的結果。
See the Pen Flex 寬度計算規則 - 3 by Wcc723 (@Wcc723) on CodePen.
由於 Flex 是按比例分配剩餘空間,因此在前面的範例中,兩者 flex-grow 都是 1 的情況下,會呈現 1:1 的結果,這次改為 1:2 那麼寬度的計算上也會改為 1:2,重點如下:
- 分配空間是依據比例(flex-grow 的總和值再重新分配)
- 是分配 剩餘的空間,已經佔用的空間不會重新分配
因此,以上方的範例來說:
- 總寬度為 600px,最左方的元素佔用 200px 寬度,因此剩餘 400px
- flex-grow 分別為 2、1,因此總和為 3
- 比例分配上為 400px / 3 = 133.33333px
- 左方寬度為 133 * 1,右方元素為 133 * 2 = 266
圖文說明:
接下來,請使用你的開發者工具檢視上方的結果(左方約為 134px,右方為 266px)。
注意,可分配的空間
flex 的可分配空間會隨著條件不同而改變,以下範例來說,中間的元素補上了 100px,我們會發現他的寬度計算會與上一個的範例有所不同。
- 中間的元素與右邊元素尺寸大小不相上下
See the Pen Flex 寬度計算規則 - 8 by Wcc723 (@Wcc723) on CodePen.
此段的計算邏輯:
- 計算出可分配的空間:總寬(600px) - 左方元素(200px) - 中間元素的固定寬(100px) = 300px
- 計算比例:300px / 3(
flex-grow
總值) = 100px - 重新分配:
- 右方元素(grow: 2) 100px * 2 = 200px
- 中間元素(basis: 100px; grow: 1) 100px + 100px * 1 = 200px
接下來,透過開發者工具會得到 接近 上述的結果。
問題:為什麼是接近上述的結果,而不是完全符合呢?
因為 flex 計算上是 分配剩餘的空間,空間上被佔用的因素非常多,如上述的 flex-basis 就是會屬於佔用空間的一種,除此之外包含元素內部的 文字、邊線、任何內容都會影響到佔用空間,因此也會影響到剩餘的空間分配。
Shrink 收縮值,分配多餘的空間
flex-shrink
與 flex-grow
運作上則是相反,shrink
是將超出的部分重新分配,確保元素不會被裁切(如果足夠被分配完)。
以下範例透過三個 flex-basis: 250px
來超出範圍,並且統一設定 flex-shrink
與 flex-grow
皆為 0(禁止伸展、收縮),可以得到以下的結果:內元素超出了外容器。
See the Pen Flex 寬度計算規則 - 4 by Wcc723 (@Wcc723) on CodePen.
接下來,將右邊兩個元素 flex-shrink
設為 1
,會看到兩個元素多餘的內容收縮到外容器內部並維持相同的寬度,最左方的元素則維持原本的寬度不變。
See the Pen Flex 寬度計算規則 - 5 by Wcc723 (@Wcc723) on CodePen.
接下來,一樣進行 2:1 的 shrink 設置實驗,左方為 flex-shrink: 1
,右方為 flex-shrink: 1
,接下來你可能會猜想兩者的尺寸應為 2: 1
吧!
See the Pen Flex 寬度計算規則 - 6 by Wcc723 (@Wcc723) on CodePen.
實際結果:當然不是~
上面有提到 shrink
是分配多餘的空間,因此不是全部的空間上都重新分配,所以運作的結果如下:
接下來,重新使用你的開發者工具,檢視上方的結果吧(會得到中間元素寬度 200px,右方元素寬度 150px)。
遵循軸線
Flex 撇除了原本的寬度、高度的空間定義,改用三個屬性(basis、grow、shrink)來定義一個容器的尺寸,不僅是為了提高容器的空間彈性,除此之外計算出來的空間尺寸還能依據 Flex 的軸線重新計算,大大增加了空間的彈性。
以下範例來說,將 Flex 主軸線切換為 flex-direction: column;
,內層元素依然可依據垂直的方式重新分配空間大小,且計算邏輯一致。
See the Pen Flex 寬度計算規則 - 3 - cloumn by Wcc723 (@Wcc723) on CodePen.
如果透過文字還是不容易理解,可以看我過去線上教學的影片 - Flex 寬度計算方法,或是Flex 完整教學