Flexbox 佈局的正確使用姿勢

發表於2017-06-29

在專案中,我們還會大量使用到flexbox的新舊屬性,但大多數人一般只會寫新屬性,舊屬性交由autoprefixer處理,但其實完成同樣功能的新舊屬性表現形式卻不盡相同。還有部分人只使用“萬能”的flex:number屬性為伸縮專案分配空間,但有些特殊情景卻無法滿足,此文為此梳理了flexbox的新舊屬性區別和分配空間的原理,為大家用flexbox佈局的專案通通渠。

Flexbox相容性

PC端的相容性
Flexbox 佈局的正確使用姿勢

移動端的相容性
Flexbox 佈局的正確使用姿勢

如上圖,為了相容IE10-11和Android4.3-,UC,我們仍需要使用Flexbox的舊屬性。

Flexbox新舊屬性

Flexbox的新屬性提供了很多舊版本沒有的功能,但是目前Android4.x和UC仍有一定市場佔有率需要相容,因此目前只使用新舊屬性都有的功能。
能實現相同功能的Flexbox新舊屬性如下表:
Flexbox 佈局的正確使用姿勢

但想象是美好的,現實是殘酷的,新舊屬性裡有那麼幾個頑固分子並不能乖乖的表現的一樣,總有那麼一點不同。
下面我們來看看是哪些新舊屬性有不同:

flex-direction:row-reverse vs box-orient:horizontal;box-direction:reverse

相同點:改變主軸方向和伸縮專案的排列順序;在ltr下伸縮專案從右到左排列。
不同點:

flex-direction:row-reverse:第一個伸縮專案向主軸起點對齊
Flexbox 佈局的正確使用姿勢

box-orient:horizontal;box-direction:reverse:最後一個伸縮專案向主軸終點對齊
Flexbox 佈局的正確使用姿勢

flex-direction:column-reverse vs box-orient:vertical;box-direction:reverse

相同點:改變主軸方向和伸縮專案的排列順序;在ltr下伸縮專案從下到上排列。
不同點:
flex-direction:column-reverse:第一個伸縮專案向主軸起點對齊。
Flexbox 佈局的正確使用姿勢

box-orient:vertical;box-direction:reverse:最後一個伸縮專案向主軸終點對齊。
Flexbox 佈局的正確使用姿勢

oreder:integer vs box-ordinal-group:integer

相同點:定義伸縮專案顯示順序。
不同點:
oreder:integer:預設值為0;可以為負值。
box-ordinal-group:integer:預設值為1;取值大於1。

flex-grow:number vs box-flex:number

相同點:定義伸縮專案的擴充套件因素。
不同點:box-flex:number同時定義了伸縮專案的縮小因素。

flex-shrink:number vs box-flex:number

相同點:定義伸縮專案的縮小因素。
不同點:box-flex:number同時定義了伸縮專案的擴充套件因素。

Flexbox分配空間原理

影響Flexbox佈局分配空間的屬性有三個,分別是flex-growflex-shrinkflex-basis

  • flex-grow:當伸縮專案在主軸方向的總寬度
  • flex-shrink:當伸縮專案在主軸方向的總寬度 > 伸縮容器,伸縮專案根據縮小因素分配總寬度超出伸縮容器的空間。
  • flex-basis:伸縮基礎,在進行計算剩餘空間或超出空間前,給伸縮專案重新設定一個寬度,然後再計算。

我們先來看看如何計算計算拉伸後的伸縮專案寬度,先簡單明瞭的給個公式,再通過栗子來驗證。

伸縮專案擴充套件寬度 = (專案容器寬度 – 專案寬度或專案設定的flex-basis總和) * 對應的flex-grow比例

拉伸後伸縮專案寬度 = 原伸縮專案寬度 + 擴充套件寬度

Flexbox 佈局的正確使用姿勢

我們來計算一下上面栗子中第一個伸縮專案拉伸後的寬度。
對應著公式一步步計算:

計算後得到第一個伸縮專案拉伸後的寬度是70px,我們通過chrome上的盒子模型來看看是否正確
Flexbox 佈局的正確使用姿勢

chrome計算的結果和我們計算的結果是一致的。

根據拉伸的計算公式是不是很容易就能推演出壓縮的計算公式呢?

伸縮專案縮小寬度 = (專案寬度或專案設定的flex-basis總和 – 專案容器寬度) * 對應的flex-shrink比例

壓縮後伸縮專案寬度 = 原伸縮專案寬度 – 縮小寬度

繼續用個栗子來驗證公式是否正確

Flexbox 佈局的正確使用姿勢

我們來計算一下上面栗子中第一個伸縮專案壓縮後的寬度。
對應著公式一步步計算:

計算後得到第一個伸縮專案壓縮後的寬度是50px,我們通過chrome上的盒子模型來看看是否正確
Flexbox 佈局的正確使用姿勢

chrome計算的結果和我們計算的結果不一樣。
Flexbox 佈局的正確使用姿勢

伸縮專案壓縮的計算方式和拉伸的不一樣,是因為壓縮會有極端情況,我們把第一個伸縮專案的flex-shrink修改為10,此時縮小寬度為( 400 - 250 ) * ( 10 / 24) = 62.5,縮小的寬度比原寬度要大,計算的壓縮後的寬度變成了負數。

為了避免這種極端情況,計算縮小比例是要考慮伸縮專案的原寬度。

正確的公式是這樣的

伸縮專案縮小寬度 = (專案寬度或專案設定的flex-basis總和 – 專案容器寬度) (對應的flex-shrink 專案寬度或專案設定的flex-basis比例)

壓縮後伸縮專案寬度 = 原伸縮專案寬度 – 縮小寬度

對應著公式一步步計算:

計算後得到第一個伸縮專案壓縮後的寬度是53.078px,和chrome上的盒子模型是一樣的。

Flexbox屬性縮寫陷阱

上面介紹的flex-growflex-shrinkflex-basis有一個縮寫的寫法flex

flex: flex-grow [flex-shrink] [flex-basis]

flex各種縮寫的值

  • flex: initial == flex: 0 1 auto
  • flex: none == flex: 0 0 auto
  • flex: auto == flex: 1 1 auto
  • flex: number == flex: number 1 0%

在實際專案中,會直接寫使用縮寫的flex來給伸縮專案分配空間,但是使用縮寫屬性會留下一些陷阱,導致表現的結果不盡如人意。

分別使用flexflex-grow來把伸縮專案拉伸填滿容器,看看錶現的差異。

首先看看使用flex-grow拉伸伸縮專案的效果

每個伸縮專案在原寬度上拉伸相同的寬度
Flexbox 佈局的正確使用姿勢

通過上面的計算拉伸後的伸縮專案寬度,可以計算第一個伸縮專案拉伸後的寬度

Flexbox 佈局的正確使用姿勢

然後我們把flex-grow:1替換成flex:1,下面是表現的效果,伸縮專案拉伸後的寬度變成一樣了。
Flexbox 佈局的正確使用姿勢

從chrome的盒子模型可看到伸縮專案拉伸後寬度變成了110px,伸縮容器等分了容器的寬度。
Flexbox 佈局的正確使用姿勢

flex:1展開後是flex:1 1 0%flex-grow:1相當於flex:1 1 auto,兩者的區別在於flex-basis的值不同。flex:1為專案寬度重新設定了寬度為0,所以可分配空間為整個容器,從公式計算上可以更直觀理解:

需要注意的Flexbox特性

無效屬性

  • column-*在伸縮容器無效
  • float和clear在伸縮專案無效
  • vertical-align在伸縮專案無效
  • ::first-line and ::first-letter在伸縮容器無效

伸縮容器中的非空字元文字節點也是伸縮專案

1 2 我是個假文字 3 4 5

Flexbox 佈局的正確使用姿勢

margin摺疊

  • 伸縮容器和伸縮專案的margin不會摺疊
  • 伸縮專案間的margin不會摺疊

舊版Flexbox的BUG

伸縮專案為行內元素要加display:block;或display:flex

到此本文結束,如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

如果本文對你有幫助,請點下贊或推薦,寫文章不容易。

相關文章