Flexbox佈局 已經是目前最爲流行的Web佈局方式之一,它給Web開發者在完成頁面或組件的UI佈局帶來了極大的靈活性和便利性。但也是由於它有極大的靈活性,裏面隱藏了一些鮮爲人知的細節,若是不是對Flexbox極爲熟悉或者對其規範極爲了解的話,其中有不少細節將會被遺漏,而這些細節又會讓你在使用的感到困惑,甚至是帶來必定的麻煩。html
此次在優化imgcook的Flexbox佈局時,從新閱讀了一次Flexbox的規範,發現本身曾忽略了部分重要信息。爲此在這篇文章中,將Flexbox佈局,CSS的書寫模式,邏輯屬性,對齊方式結合在一塊兒整理了一篇筆記,但願對於想了解或使用Flexbox碰到痛楚的同窗有所幫助。前端
術語的統一有助於咱們後面更好的討論和解決問題。用下圖來描述Flexbox中的術語:算法
主軸和側軸只有在Flexbox佈局體系中才有這樣的概念,並非水平方向永遠都是主軸(Main Axis),垂直方向永遠是側軸(Cross Axis)。主軸和側軸除了會受Flexbox中的
flex-direction
取值的影響以外,還會受CSS的書寫模式writing-mode
和direction
以及HTML的dir
屬性的影響!瀏覽器
CSS Box Alignment Module Level 3 引入了兩個新的概念,即 塊軸(Block Axis)和 內聯軸(Inline Axis) :markdown
同時 塊軸(Block Axis)又常稱爲列(Column), 內聯軸(Inline Axis)又常稱爲行(Row):ide
雖然目前爲止在 Flexbox規範和Grid規範中都有自身關於對齊方式的描述,但CSS中有關於對齊方式都將收口到Box Alignment 模塊中;爲此後面對說軸的說法更多的是「 塊軸」 和 「 行內軸」,結合到Flexbox佈局中,軸的對應關係是:oop
塊軸和行內軸一樣受CSS的書寫模式
writing-mode
和direction
以及HTML的dir
屬性影響。只不過,在Flexbox佈局中,還受flex-direction
屬性的影響。佈局
CSS Writing Modes Level 3 規範中的 writing-mode
和 direction
以及HTML中的 dir
屬性對於Flexbox中的主軸和側軸都會有影響,將會改變主軸和側軸的方向。flex
塊軸 、 內聯軸 、 書寫模式 的出現以後,就有了 塊起點(Block Start)、塊終點(Block End)、內聯起點(Inline Start)和 內聯終點(Inline End):
若是放到Flexbox佈局中:
同時 CSS Logical Properties and Values Level 1 規範中引入了 block-start
、 block-end
、 inline-start
和 inline-end
, 但它們和Flexbox中,Grid中以入Box Alignment中的 flex-start
、 start
、 flex-end
和 end
是不等同的,也不是同一領域中的概念。這幾個屬性對應的是物理屬性中的 top
、 right
、 bottom
和 left
:
也就是說,引入CSS邏輯屬性以後,CSS盒模型將分 物理盒模型 和 邏輯盒模型 :
CSS屬性也今後以後有 邏輯屬性 和 物理屬性 之分:
注意,CSS邏輯屬性也受CSS書寫模式 writing-mode
、 directioin
屬性和HTML的 dir
屬性影響,並且不一樣組合之下也不一樣:
在Flexbox佈局模塊中,Flex容器中可能會包含一個或多個Flex項目。而Flex容器和Flex項目都有其自身的尺寸大小,那麼就會有Flex項目尺寸大小之和大於或小於Flex容器的情景:
在元素上使用 display
設置值爲 flex
或 inline-flex
,該容器會成爲 Flex容器,該容器下的子元素,包括 文本節點,僞元素。
使用 flex
和 inline-flex
的具體場景:
若是元素顯式設置了 display
的值爲 flex
或 inline-flex
,Flex項目在未顯式設置與尺寸大小有關的屬性時,Flex項目都將會按其內容大小來計算自身大小。
display: flex
時,Flex容器未顯式設置與寬度相關的屬性時,其寬度與其父容器等同(至關於 width: 100%
)display: inline-flex
時,Flex容器未顯式設置與寬度相關的屬性時,其寬度等同於全部Flex項目的寬度和當Flex容器中全部Flex項目全部寬和大於Flex容器時:
display: flex
時,Flex項目會溢出Flex容器display: inline-flex
時,Flex項目會撐大Flex容器,有可能形成Flex容器溢出其父元素(或祖先元素)使用 display: inline-flex
時最好結合 min-width
和 min-height
一塊兒使用。不建議顯式設置 width
和 height
。
display
設置爲 flex
時,Flex容器從表現形式上相似於塊容器,事實它是一個Flex容器,上下文格式是FFC(Flexbox Formatting Content),所以運用於塊容器(Block Formatting Content)上的一些佈局屬性就再也不適用,好比:
column-*
屬性在Flex容器上不起做用float
和 clear
屬性在Flex項目上不起做用,也不會讓Flex項目脫離文檔流vertical-align
屬性在Flex項目上不起做用::first-line
和 ::first-letter
在Flex容器上不起做用,並且Flex容器不會爲其祖先提供首行或首字母格式化有一點須要注意, 若是元素的 display
的值爲 inline-flex
,而且該元素顯式的設置了 float
或 position
的值爲 relative
、 absolute
或 fixed
,那麼 display
的計算值是 flex
, 即 Flex容器表現行爲和 display: flex
等同 。
在Flex容器中顯式使用 flex-direction
能夠指定主軸方向,若是未顯式設置 flex-direction
屬性,Flex容器則會採用其默認值 row
。
上圖展現的僅是閱讀方式是 LTR(Left-to-Right),如無特殊聲明,接下來的文檔不會因閱讀方式(即CSS的 writing-mode
、 direction
和HTML的 dir
屬性)列出不一樣的示意圖。
除非須要顯式的修改主軸方向,才須要在Flex容器上顯式設置 flex-directioin
, 好比像下圖這種排版本方式:
_flex-direction: column
_
row-reverse
和默認值 row
表現偏偏相反,適用於下面這樣佈局場景:
在Flexbox佈局中, flex-direction
在指定Flex容器主軸方向時,也會對Flex項目的排列順序有影響(在不改變DOM結構,要實現反方向排版時,很是適合)。除了 flex-direction
能夠影響Flex項目排列順序以外,在Flex項目中顯式使用 order
屬性也能夠,而且能夠在不影響DOM結構,按照你本身任意想要的意圖進行排序。
目前在imgcook中使用Flexbox佈局時,在Flex容器上都會顯式的設置 flex-direction
的值,即便是默認值: row
。在佈局算法優化中,能夠作相應的處理,只有在非 row
時纔在Flex容器上顯式設置 flex-direction
:
使用 flex-wrap
能夠控制Flex項目在Flex容器換行的方式:
只有全部Flex項目寬度總和大於Flex容器主軸尺寸時,設置 flex-wrap
屬性才能生效。
flex-wrap
取值爲非 nowrap
(即 wrap
和 wrap-reverse
)均可以讓Flex項目換行(列)顯式,其中 wrap-reverse
表現行爲和 wrap
恰好相反。
組合效果 | 表現效果 |
---|---|
效果1 |
![]() |
效果2 |
![]() |
效果3 |
![]() |
效果4 |
![]() |
效果5 |
![]() |
效果6 |
![]() |
效果7 |
![]() |
效果8 |
![]() |
flex-direction
和 flex-wrap
能夠簡寫成 **flex-flow
**。 flex-flow
使用時能夠只顯式設置一個值,也能夠顯式設置兩個值:
flex-flow
只顯式設置一個值,而且該值和 <flex-direction>
相匹配時, flex-wrap
會取值 initial
flex-flow
只顯式設置一個值,而且該值和 <flex-wrap>
相匹配時, flex-direction
會取值 initial
flex-flow
顯式設置兩個值時, flex-direction
和 flow-wrap
沒有前後順序之分,便可 flex-flow: column wrap
和 flex-flow: wrap column
等同在Flex容器中使用 justify-content
來控制Flex項目在Flex容器主軸方向的對齊方式,也能夠用來分配Flex容器中主軸方向的剩餘空間。使用 justify-content
分配Flex容器剩餘空間,主要是將剩餘空間按不一樣的對齊方式,將剩餘空間分配給Flex項目的兩側,即控制Flex項目與Flex項目之間的間距。
justify-content
存在兩個規範中:
在Flexbox 佈局模塊中, justify-content
取值只要有如下六種:
須要注意 space-between
、 space-around
和 space-evenly
三者的差別:
space-between
會讓第一個Flex項目的盒子起始邊緣與Flex容器主軸起點相穩合,最後一個Flex項目的盒子結束邊緣與Flex容器主軸終點相穩合,其它相鄰Flex項目之間間距相等。當Flex容器中只有一個Flex項目時,其表現行爲和 flex-start
等同space-around
會讓第一個Flex項目的盒子起始邊緣與Flex容器主軸起點間距和最後一個Flex項目的盒子結束邊緣與Flex容器主軸終點間距相等,而且等於其餘相鄰兩個Flex項目之間間距的一半。當Flex容器中只有一個Flex項目時,其表現行爲和 center
等同space-evenly
會讓第一個Flex項目的盒子起始邊緣與Flex容器主軸起點間距和最後一個Flex項目的盒子結束邊緣與Flex容器主軸終點間距相等,而且等於其餘相鄰兩個Flex項目之間間距。當Flex容器中只有一個Flex項目時,其表現行爲和 center
等同若是Flex容器沒有額外的剩餘空間,或者說剩餘空間爲負值時, justify-content
的值表現形式:
flex-start
會讓Flex項目在Flex容器主軸結束點處溢出flex-end
會讓Flex項目在Flex容器主軸起點處溢出center
會讓Flex項目在Flex容器兩端溢出space-between
和 flex-start
相同space-around
和 center
相同space-evenly
和 center
相同在Flexbox佈局中,可使用這些屬性很好控制Flex容器的剩餘空間,好比:
在Flexbox容器中使用 align-items
來控制Flex項目在側軸方向的對齊方式。
align-items
的默認值是 stretch
,但只有Flex項目示顯式設置 height
(或 width
)值,Flex項目纔會被拉伸填滿整個Flex容器。
若是Flex容器沒有剩餘空間或剩餘空間爲負值是:
flex-start
會讓Flex項目在Flex容器側軸終點處溢出flex-end
會讓Flex項目在Flex容器側軸起點處溢出center
會讓Flex項目在Flex容器側軸兩側溢出baseline
會讓Flex項目在Flex容器側軸終點溢出,有點相似於 flex-start
align-content
只適用於Flex容器在沒有足夠空間(全部Flex項目寬度之和大於Flex容器主軸尺寸),而且顯式設置 flex-wrap
的值爲非 wrap
時。
align-content
表現行爲有點相似於 justify-cotent
控制Flex項目在主軸方向的對齊方式(分配Flex容器主軸剩餘空間),而 align-content
能夠用來控制多行狀態下,行在Flex容器側軸的對齊方式(分配Flex容器側軸剩餘空間)。能夠把 align-content
狀態下側軸中的整行看成是 justify-content
狀態下單個Flex項目。
align-content
還有一點不一樣之處,多了一個 stretch
值。當Flex容器中全部行的尺寸之和大於Flex容器側軸尺寸(Flex容器側軸沒有可用空間或可用空間爲負值)時,各值表現行爲:
flex-start
會讓Flex容器的行在側軸結束點溢出flex-end
會讓Flex容器的行在側軸起點溢出center
會讓Flex容器行在側軸兩端溢出stretch
表現行爲相似於 flex-start
space-around
表現行爲相似於 center
space-between
表現行爲相似於 flex-start
space-evenly
表現行爲相似於 center
gap
用來控制Flex項目之間的間距,但會忽略Flex項目與Flex容器邊緣的間距:
在Flex容器上可使用 justify-content
、 align-content
以及 align-items
分配Flex容器主軸和側軸的空間(控制Flex容器中全部Flex項目對齊方式)。若是你須要對Flex項目個體對齊方式作處理,可使用 align-self
:
align-self
取不一樣值的效果:
Flex項目的 align-self
顯式設置值爲 auto
時不會覆蓋Flex容器的 align-items
;另外若是在Flex項目上顯式設置 margin
的值爲 auto
時,Flex項目的 align-self
值將會失效。
相似上圖這樣的場景, align-self
就很是實用。
在Flex容器中使用 flex-direction
能夠對Flex容器中的全部Flex項目按「 LTR」、「 RTL」、「 TTB」 或 「 BTT」 方向排列。
flex-driection: row
flex-direction: row-reverse
flex-direction: column
flex-direction: column-reverse
在Flex項目上,還可使用 order
指定具體的數值,在不改變DOM結構之下對Flex項目進行排序,其中數值越大,越在日後排:
在一些左右,上下互換順序的時候,除了 flex-direction
以外,還能夠在Flex項目設置 order
:
Flex項目中使用 flex
屬性能夠根據Flex容器的可用空間對自身作伸縮計算,其包含三個子屬性: flex-basis
、 flex-shrink
和 flex-grow
。這幾個屬性都有其初始值:
flex-grow
的初始值爲 0
flex-shrink
的初始值爲 1
flex-basis
的初始值爲 auto
即 flex
的三個子屬性: flex-grow
(擴展比率)、 flex-shrink
(收縮比率)和 flex-basis
(伸縮基準)。這三個屬性能夠控制Flex項目,具體的表現以下:
flex-grow
:設置Flex項目的擴展比率,讓Flex項目獲得(擴展)多少Flex容器剩餘空間(Positive Free Space),即Flex項目可能會變大flex-shrink
:設置Flex項目收縮比率,讓Flex項目減去Flex容器不足的空間(Negative Free Space),即Flex項目可能會變小flex-basis
:Flex項目未擴展或收縮以前,它的大小,即指定了Flex項目在主軸方向的初始大小flex
屬性能夠指定 1個值(單值語法) 、 2個值(雙值語法) 或 3個值(三值語法) 。
單值語法:值必須爲如下其中之一:
<number>
),好比 flex: 1
,這個時候它會被看成 <flex-grow>
的值width
)值,好比 flex: 30vw
,這個時候它會被看成 <flex-basis>
的值none
、 auto
或 initial
(即初始值)雙值語法:第一個值必須爲一個無單位數值,而且它會被看成 <flex-grow>
的值;第二個值必須爲如下之一:
<number>
),它會被看成 <flex-shrink>
的值width
)值,它會被看成 <flex-basis>
的值三值語法:
<number>
),而且它會被看成 <flex-grow>
的值<number>
),而且它會被看成 <flex-shrink>
的值width
)值,而且它會被看成 <flex-basis>
的值flex
屬性的取值能夠是:
auto
:Flex項目會根據自身的 width
和 height
來肯定尺寸,但Flex項目根據Flex容器剩餘空間進行伸縮。其至關於 flex: 1 1 auto
initial
:Flex項目會根據自身的 width
和 height
來設置尺寸。它會縮短自身以適應Flex容器,但不會伸長並吸取Flex容器中的額外剩餘空間來適應Flex容器。其至關於 flex: 0 1 auto
none
:Flex項目會根據自身的 width
和 height
來設置尺寸。它是徹底非彈性的(既不會縮短,也不會伸長來適應Flex容器)。其至關於 flex: 0 0 auto
<flex-grow>
:定義Flex項目的 flex-grow
屬性,取值爲 <number>
<flex-shrink>
:定義Flex項目的 flex-shrink
屬性,取值爲 <number>
<flex-basis>
:定義Flex項目的 flex-basis
屬性。若值爲 0
,則必須加上單位,以避免被視做伸縮性flex-grow
計算flex-grow
計算公式:
示例:
假設Flex容器中有四個Flex項目,具體參數:
80vw
10vw
10vw x 4 = 40vw
80vw - 40vw = 40vw
flex-grow
的值分別是 0
、 1
、 2
和 3
,全部Flex項目的 flex-grow
總和爲 0 + 1 + 2 + 3 = 6
flex-grow 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-grow 值 |
0 | 1 | 2 | 3 | 0 + 1 + 2+ 3 = 6 |
Flex項目寬度 | 10vw | 10vw | 10vw | 10vw | 10vw x 4 = 40vw |
Flex容器寬度 | 80vw | ||||
Flex容器剩餘空間 | 80vw - 40vw = 40vw | ||||
Flex項目新寬度 | ? | ? | ? | ? |
計算過程:
計算出來的結果:
flex-grow 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-grow 值 |
0 | 1 | 2 | 3 | 0 + 1 + 2+ 3 = 6 |
Flex項目寬度 | 10vw | 10vw | 10vw | 10vw | 10vw x 4 = 40vw |
Flex容器寬度 | 80vw | ||||
Flex容器剩餘空間 | 80vw - 40vw = 40vw | ||||
Flex項目新寬度 | 10vw | 16.667vw | 23.333vw | 30vw |
flex-grow
的取值還能夠是 小數值 。若是將上面示例中的 flex-grow
的值分別換成 0
、 0.1
、 0.2
和 0.3
,這個時候 flex-grow
的總和(全部Flex項目的 flex-grow
和)就是 0.6
,該值小於 1
。這個時候,Flex項目一樣會根據 flex-grow
增加因子來瓜分Flex容器的剩餘空間,Flex自身寬度也會變大,但Flex容器的剩餘空間不會被所有瓜分完,由於全部 flex-grow
和小於 1
。就該示例下,只瓜分了 Flex容器剩餘空間寬度的 60%
。
若是 flex-grow
和小於 1
,其計算公式以下:
flex-grow 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-grow 值 |
0 | .1 | .2 | .3 | 0 + 1 + 2+ 3 = .6 |
Flex項目寬度 | 10vw | 10vw | 10vw | 10vw | 10vw x 4 = 40vw |
Flex容器寬度 | 80vw | ||||
Flex容器剩餘空間 | 80vw - 40vw = 40vw | ||||
Flex項目新寬度 | 10vw | 14vw | 18vw | 22vw |
即便Flex容器中全部Flex項目的 flex-grow
和大於 1
,但也不能夠絕對地說,Flex項目能夠根據自身的 flex-grow
所佔比率來瓜分Flex容器的剩餘空間。由於元素的尺寸會受 max-width
的影響。當Flex項目顯式設置了 max-width
的值時,當Flex項目根據flex-grow
計算出來的寬度大於 max-width
時,Flex項目會按 max-width
的值爲準。好比咱們在前面的示例上,給全部Flex項目設置一個 max-width
的值爲 18vw
,此時計算過程和結果以下:
flex-grow 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-grow 值 |
0 | 1 | 2 | 3 | 0 + 1 + 2+ 3 = 6 |
Flex項目寬度 | 10vw | 10vw | 10vw | 10vw | 10vw x 4 = 40vw |
Flex容器寬度 | 80vw | ||||
Flex容器剩餘空間 | 80vw - 40vw = 40vw | ||||
Flex項目計算出的新寬度 | 10vw | 16.667vw | 23.333vw | 30vw | |
Flex項目設置最大寬度 | 18vw | 18vw | 18vw | 18vw | |
Flex項目最終寬度 | 10vw | 16.667vw | 18vw | 18vw |
這個時候Flex容器剩餘空間並無所有用完, 40vw - 0vw - 6.667vw - 8vw - 8vw = 17.333vw
,即Flex容器還有 17.333vw
的剩餘空間。
若是Flex項目沒有顯式設置與寬度有關的屬性(包括 flex-basis
),那麼 flex-grow
在計算時,Flex項目會按其內容的寬度來計算。
從上圖能夠獲得:
804px
43.36px
、 92.09px
、 140.83px
和 189.56px
,全部Flex項目寬度的總和爲 465.84px
804px - 465.84px = 338.16px
flex-grow
值爲 1
,即 全部Flex項目的 flex-grow
總和爲 4
將相應的值套用到 flex-grow
的公式中,能夠獲得:
flex-grow 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-grow 值 |
1 | 1 | 1 | 1 | 1 x 4 = 4 |
Flex項目寬度 | 43.36px | 92.09px | 148.83px | 189.56px | 465.84px |
Flex容器寬度 | 804px | ||||
Flex容器剩餘空間 | 338.16px | ||||
Flex項目新寬度 | 127.9px | 176.63px | 225.37px | 274.1px |
注意,不一樣的瀏覽器對小數處理有差別。
flex-shrink
計算flex-shrink
計算公式:
示例:
假設Flex容器有四個Flex項目,具體參數以下:
40vw
15vw
15vw x 4 = 60vw
40vw - 60vw = -20vw
flex-shrink
的值分別是 0
、 1
、 2
和 3
,全部Flex項目的 flex-shrink
總和爲 0 + 1 + 2 + 3 = 6
flex-shrink 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-shrink 值 |
0 | 1 | 2 | 3 | 0 + 1 + 2+ 3 = 6 |
Flex項目寬度 | 15vw | 15vw | 15vw | 15vw | 15vw x 4 = 60vw |
Flex容器寬度 | 40vw | ||||
Flex容器不足空間 | 60vw - 40vw = 20vw | ||||
Flex項目新寬度 | ? | ? | ? | ? |
計算過程:
計算出來的結果:
flex-shrink 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-shrink 值 |
0 | 1 | 2 | 3 | 0 + 1 + 2+ 3 = 6 |
Flex項目寬度 | 15vw | 15vw | 15vw | 15vw | 15vw x 4 = 60vw |
Flex容器寬度 | 40vw | ||||
Flex容器不足空間 | 60vw - 40vw = 20vw | ||||
Flex項目收縮比例 | 0 | 0.1667 | 0.333 | 0.5 | |
Flex項目新寬度 | 15vw | 11.67vw | 8.33vw | 5vw |
flex-shrink
的計算還能夠甚至另外一個公式來計算:
flex-shrink
和 flex-grow
相似,也能夠取小數值。若是Flex容器中全部Flex項目的 flex-shrink
總和小於 1
,那麼Flex容器的不足空間就不會被Flex項目按收縮因子瓜分完,Flex項目會依舊會溢出Flex容器。
flex-shrink
總和小於 1
時,其計算公式以下:
基於上面的示例,把Flex項目的 flex-shrink
分別設置爲 0
、 0.1
、 0.2
和 0.3
,計算過程以下:
flex-shrink 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-shrink 值 |
0 | 0.1 | 0.2 | 0.3 | 0.6 |
Flex項目寬度 | 15vw | 15vw | 15vw | 15vw | 15vw x 4 = 60vw |
Flex容器寬度 | 40vw | ||||
Flex容器不足空間 | 60vw - 40vw = 20vw | ||||
Flex項目新寬度 | 15vw | 13vw | 11vw | 9vw |
即便Flex容器中全部Flex項目的 flex-shrink
和大於 1
,但也不能夠絕對地說,Flex項目能夠根據自身的 flex-shrink
所佔比率來瓜分Flex容器的不足空間。由於元素的尺寸會受 min-width
的影響。當Flex項目顯式設置了 min-width
的值時,當Flex項目根據 flex-shrink
計算出來的寬度小於 min-width
時,Flex項目會按 min-width
的值爲準。好比咱們在前面的示例上,給全部Flex項目設置一個 min-width
的值爲 10vw
,此時計算過程和結果以下:
flex-shrink 公式中變量名稱 |
Flex1 | Flex2 | Flex3 | Flex4 | 總數 |
---|---|---|---|---|---|
Flex項目的 flex-shrink 值 |
0 | 1 | 2 | 3 | 0 + 1 + 2+ 3 = 6 |
Flex項目寬度 | 15vw | 15vw | 15vw | 15vw | 15vw x 4 = 60vw |
Flex容器寬度 | 40vw | ||||
Flex容器不足空間 | 60vw - 40vw = 20vw | ||||
Flex項目收縮比例 | 0 | 0.1667 | 0.333 | 0.5 | |
Flex項目設置最小寬度 | 10vw | 10vw | 10vw | 10vw | |
Flex項目計算出的新寬度 | 15vw | 11.67vw | 8.33vw | 5vw | |
Flex項目最終寬度 | 15vw | 11.67vw | 10vw | 10vw |
在這個狀況之下,Flex項目的最終寬度總和仍是會大於Flex容器寬度,Flex項目一樣會溢出Flex容器。
flex-shrink
和 flex-grow
還有一點類似,那就是未顯式給Flex容器的Flex項目顯式設置與寬度有關的屬性時,那麼Flex項目的初始寬度會以其內容的寬度做爲基準計算值。
flex-shrink
有一點和 flex-grow
徹底不一樣,若是某個Flex項目按照 flex-shrink
計算出來的新寬度趨向於 0
時,Flex項目將會按照該元素的 min-content
的大小來設置寬度,同時這個寬度將會轉嫁到其餘Flex項目,再按相應的收縮因子進行收縮。
好比咱們將第四個Flex項目的 flex-shrink
的值從 3
改成 9
。根據上面提供的公式,能夠獲知,Flex項目4的新寬度等於 15vw - (20vw ÷ 12) × 9 = 0
計算出來的寬度爲 0
,但實際上這個時候渲染出來的寬度是該項目的 min-content
(該示例就是「shrink」單詞的寬度,以下圖所示),大約 47.95px
(約 3.66vw
)。那麼這個值將會分紅 3
份(由於該例另外三個Flex項目的 flex-shrink
是 0
、 1
和 2
),而且對應的Flex項目會繼續分配本應Flex項目4要收縮的寬度。即:
15vw - 20 ÷ 12 × 0 - 3.66 ÷ 3 × 0 = 15vw
(約 196.5px
)15vw - 20 ÷ 12 × 1 - 3.66 ÷ 3 × 1 = 12.113vw
(約 158.6847px
)15vw - 20 ÷ 12 × 2 - 3.66 ÷ 3 × 2 = 9.227vw
(約 120.869px
)瀏覽器視窗寬度在 1310px
狀態下渲染出來的結果以下:
在Flexbox佈局模塊中,基於前面提到的Flex容器的對齊屬性、Flex項目中的 flex-shrink
和 flex-grow
咱們就能夠很好的處理Flex容器的剩餘空間和不足空間:
flex-grow
,Flex項目會根據擴展因子分配Flex容器剩餘空間;在未設置 flex-grow
時,在Flex容器中是否設置了對齊方式,若是是,那麼會按對齊方式分配Flex容器剩餘空間,若是不是,Flex容器剩餘空間不變flex-shrink
值爲 0
,Flex項目不會收縮,Flex項目溢出Flex容器;若是未顯式設置 flex-shrink
值,Flex項目分平均分配Flex容器不足空間,Flex項目會變窄(Flex項目的 flex-shrink
的默認值爲 1
),若是顯式設置了 flex-shrink
的值爲非 0
的不一樣值,那麼Flex項目會按照不一樣的收縮因子分配Flex容器不足空間,Flex項目一樣會變窄具體的咱們能夠繪製一張這方面的流程圖:
flex-basis
計算flex-basis
的計算相對於 flex-grow
和 flex-shrink
更略爲複雜,由於它和Flex項目的 內容(Content) 、** width
**、 min-width
和 max-width
都有關係。這裏的關係指的就是它們之間的權重關係,簡單地說,在Flex項目中同時出現這幾個屬性時,最終由誰來決定Flex項目的寬度。
在Flexbox佈局中,可使用 flex-basis
來實始化Flex項目尺寸,即 在任何Flex容器空間(剩餘空間或不足空間)分配發生以前初始化Flex項目尺寸。
事實上,在Flexbox佈局模塊中 設置Flex項目的尺寸大小存在一個隱式的公式:
content
➜width
➜flex-basis
簡單地說,若是Flex項目未顯式指定 flex-basis
的值,那麼 flex-basis
將回退到 width
(或 inline-size
)屬性;若是未顯式指定 width
(或 inline-size
)屬性的值,那麼 flex-basis
將回退到基於Flex項目內容計算寬度。不過,決定Flex項目尺寸大小,還受 flex-grow
和 flex-shrink
以及Flex容器大小的影響。並且Flex項目 最終尺寸 會受 min-width
、 max-width
(或 min-inline-size
、 max-inline-size
)屬性限制。這一點必須得注意。
來看一個示例:
<div class="flex__container">
<div class="flex__item"></div>
<div class="flex__item"></div>
<div class="flex__item"></div>
<div class="flex__item"></div>
</div>
複製代碼
.flex__container {
width: 600px;
display: flex;
border: 1px dashed #f36;
align-items: stretch;
}
複製代碼
Flex項目不顯式的設置任何與尺寸大小有關係屬性,即用 content
來撐開Flex項目。
<div class="flex__container">
<div class="flex__item">Lorem ipsum dolor sit amet</div>
<div class="flex__item">Lorem ipsum dolor sit amet consectetur adipisicing elit</div>
<div class="flex__item">Fugiat dolor nihil saepe. Nobis nihil minus similique hic quas mollitia.</div>
<div class="flex__item">Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias consequuntur sequi suscipit iure fuga ea!</div>
</div>
複製代碼
在這個示例中,並無顯式給Flex項目設置 flex-basis
屬性,此時 flex-basis
會取默認值 auto
:
顯式給Flex項目設置 width
值。
:root {
--width: 120px;
}
.flex__item {
width: var(--width);
}
複製代碼
這個時候全部Flex項目寬度都是相等的:
瀏覽器計算出來的 flex-basis
值依舊爲 auto
,但顯式的設置了 width: 120px
,最終 width
屬性的值決定了Flex項目的尺寸大小。
顯式給Flex項目設置 flex-basis
值,即Flex項目同時有 width
和 flex-basis
值。
:root {
--width: 120px;
--flexBasis: 150px;
}
.flex__container {
width: 800px;
}
.flex__item {
width: var(--width);
flex-basis: var(--flexBasis);
}
複製代碼
雖然在Flex項目同時顯式設置了 width
和 flex-basis
,但Flex項目最終的尺寸大小採用了 flex-basis
的值:
在Flexbox佈局模塊中影響Flex項目尺寸大小應該根據其隱式公式(即 content
➜ width
➜ flex-basis
)來進行判斷。若是要顯式給Flex項目設置尺寸大小,其最佳方式是 使用 flex-basis
,而不是 width
(或 inline-size
)。
最後還有一點千萬別忘記:
使用 flex-basis
時會受min-width
和 max-width
(或邏輯屬性中min-inline-size
或max-inline-size
)的限制。
在CSS中,若是元素同時出現 width
、 min-width
和 max-width
屬性時,其權重計算遵循如下規則:
width
大於 max-width
時,元素的 width
等於 max-width
,即 max-width
能覆蓋 width
( max-width
勝出)width
小於 min-width
時,元素的 width
等於 min-width
,即 min-width
能覆蓋 width
( min-width
勝出)min-width
大於 max-width
時, min-width
優先級將高於 max-width
( min-width
勝出)若是Flex項目同時出現 width
、 flex-basis
和 min-width
時,具體的運算過程以下:
content
➜ width
➜ flex-basis
,判斷出運用於Flex項目的值,即 flex-basis
會運用於Flex項目 ( flex-basis
勝出)width
小於 min-width
時,Flex項目的 width
等於 min-width
,即 min-width
能覆蓋 width
(** min-width
勝出**)這樣一來,若是 flex-basis
小於 min-width
時,Flex項目的寬度會取值 min-width
,即 min-width
覆蓋 flex-basis
(min-width
勝出)。
若是Flex項目同時出現 width
、 flex-basis
和 max-width
時,具體的運算過程以下:
content
➜ width
➜ flex-basis
,判斷出運用於Flex項目的值,即 flex-basis
會運用於Flex項目( flex-basis
勝出)width
大於 max-width
時,Flex項目的 width
等於 max-width
,即 max-width
能覆蓋 width
( max-width
勝出)這樣一來,若是 flex-basis
大於 max-width
時,Flex項目的寬度會取值 max-width
,即 max-width
覆蓋 flex-basis
( max-width
勝出)。
若是Flex項目同時出現 width
、 flex-basis
、 min-width
和 max-width
時,會在上面的規則上增長新的一條規則來進行判斷:
min-width
大於 max-width
時, min-width
優先級將高於 max-width
( min-width
勝出)。那麼套用到Flex項目中:
flex-basis
大於 max-width
,Flex項目的寬度等於 max-width
,即 max-width
能覆蓋 flex-basis
( max-width
勝出)flex-basis
小於 min-width
時,Flex項目的寬度會取值 min-width
,即 min-width
覆蓋 flex-basis
(** min-width
勝出**)因爲 min-width
大於 max-width
時會取 min-width
,有了這個先取條件咱們就能夠將 flex-basis
和 min-width
作權重比較,即:** flex-basis
會取 min-width
。反過來,若是 min-width
小於 max-width
時則依舊會取 max-width
,同時要是 flex-basis
大於 max-width
就會取 max-width
**。
若是你理解了的話,可使用更簡單的規則來決定用於Flex項目的尺寸。
首先根據 content
➜ width
➜ flex-basis
來決定用哪一個來決定用於Flex項目。若是Flex項目顯式設置了 flex-basis
屬性,則會忽略 content
和 width
。並且 min-width
是用來設置Flex項目的下限值; max-width
是用來設置Flex項目的上限值。
用一個簡單的流程圖來描述:
注,Flex項目上的 flex-shrink
和 flex-grow
也會影響Flex項目尺寸大小!
margin
在Flex項目顯式設置 margin
的值爲 auto
能夠靈活的控制單個Flex項目在Flex容器中的位置:
好比像下圖這樣的效果,使用 margin-left: auto
就很是的實用:
針對這個案例,較好的方案對於內部元素不顯式設置任何關於 padding
和 margin
的屬性。人工實現可能會像下面這樣:
<div class="flex__container">
<span class="coupon">卷</span>
<span class="divider"></span>
<span class="price">¥1000</span>
</div>
複製代碼
.flex__container {
display: inline-flex;
min-width: 200px;
height: 60px;
border: 1px solid rgba(255, 0, 54, 1);
background-color: rgba(255, 0, 54, 0.1);
border-radius: 4px;
color: #ff0036;
font-size: 24px;
font-weight: 400;
}
.flex__container > span {
display: inline-flex;
justify-content: center;
align-items: center;
}
.divider {
border-right: 1px dashed currentColor;
}
.coupon {
min-width: 50px;
}
.price {
flex: 1;
min-width: 0;
padding: 0 10px;
}
複製代碼
inline-flex
,而且給其設置一個 min-width
(默認狀況下等同於Sketch設計稿)和 一個 height
width
1px
的分割線,可使用 border
或者定死寬度 width
flex: 1
,讓該部分佔用Flex容器的剩餘空間padding-left
和 padding-right
這篇筆記涉及到了Flexbox規範中的大部份內容以及一些臨界點,在使用Flexbox來完成UI上的佈局除了文章中提到的一些基礎內容和細節以外,還有一些其餘的東西。好比Flex容器中的定位,層級計算等,Flex容器和Flex項目碰到overflow
以及Flex容器中的滾動計算等。這些對於場景具備較強的指定性,對於邊界的處理也過於複雜。在咱們日常使用Flexbox不多甚至不怎麼會碰到。所以沒有在文章中羅列。
若是你在使用Flexbox,特別是在使用imgcook自動還原UI,效果和你預期不同,或者有不合理的地方,均可以隨時來撩偶。