flex佈局更有效的實現對齊,空間分配。最近又學習下flex子元素的尺寸計算規則,主要是flex-grow
, flex-shrink
的計算規則的學習。css
定義了flex元素佈局起始點和方向,flex子元素在主軸上依次放置。
主軸有4個方向,經過flex-direction
指定:git
就是flex容器content矩形(不包含padding, border, margin區域)在主軸方向的尺寸。github
交叉軸就是跟主軸錘子的方向,主要用於flex元素的對齊。ide
就是flex容器content矩形(不包含padding, border, margin區域)在Cross軸方向的尺寸。佈局
display爲flex
,inline-flex
,的元素,也叫flex容器。學習
Tip:flex
flex box的子元素,不包含流外子元素( absolute, fix元素),可是包含float元素。ui
flex子元素在主軸上的比例依賴這三個CSS屬性:flexbox
其中:
flex-basis + flex-grow組合控制着伸
flex-basis + flex-shrink組合控制着縮
因此要肯定flex子元素在主軸上的比例,首先要肯定使用哪一種組合。spa
flex-basis
屬性指定在任何空間分配發生以前初始化flex子元素的尺寸,更確切的說flex-basis
屬性指的flex子元素盒模型(box-sizing)的尺寸,因此跟flex子元素width(height)取值邏輯相似,若是box-sizing=content,則flex-basis也不包含padding和border區域。
flex-basis + flex-grow
組合。flex-basis + flex-shrink
組合。若是存在正自由空間(positive free space),則採用flex-basis + flex-grow
組合計算flex子元素在主軸上的比例。把正自由空間比做蛋糕的話,flex-grow
表示但願分得蛋糕的量:
flex-grow: 0.2
表示但願得到20%的蛋糕;flex-grow: 1
表示但願得到100%整個蛋糕(有點過度啊,不考慮其餘兄弟);flex-grow: 2
表示但願得到200%的蛋糕(這是明搶啊,態度很明確)。但畢竟蛋糕就一個,flex容器儘可能知足felx子元素的要求,採用一種簡單的按照比例分蛋糕方式:
flex-grow
得出總和,簡稱SUM_flex_grow;正自由空間尺寸 * flex_grow / Max(SUM_flex_grow, 1)
。function demo1() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexGrow: 1, marginRight: 10}}>One</div> <div className="item" style={{flexBasis: 150, flexGrow: 2, }}>Two</div> </div> <style jsx>{` .flex { display: flex; width: 600px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; } `}</style> </> ) }
解析:
計算剩餘自由空間
100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right)
= 150px150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)
= 190px600px - 150px - 190px
= 260px,即存在正剩餘空間。計算各個flex子元素增加尺寸
1 + 2
= 3,即大於1 ,一個蛋糕不夠分,只能按照比例分了。260px * 1 / Max(1, 1 + 2)
= 260px * 1 / (1 + 2)
= 86.67px260px * 2 / Max(1, 1 + 2)
= 260px * 2 / (1 + 2)
= 173.33pxfunction demo3() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexGrow: 0.2, marginRight: 10}}>One</div> <div className="item" style={{flexBasis: 150, flexGrow: 0.3, }}>Two</div> </div> <style jsx>{` .flex { display: flex; width: 600px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; } `}</style> </> ) }
解析:
計算剩餘自由空間
100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right)
= 150px150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)
= 190px600px - 150px - 190px
= 260px,即存在正剩餘空間。計算各個flex子元素增加尺寸
0.2 + 0.3 = 0.5
,即小於1 ,一個蛋糕能知足你們需求,直接分給各個flex子元素。260px * 0.2 / Max(1, 0.5)
= 260px * 0.2
= 52px260px * 0.3 / Max(1, 0.5)
= 260px * 0.3
= 78px注意:
留意該栗子中:
box-sizing=border-box
max-width=150px
function demo4() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexGrow: 1, marginRight: 10, maxWidth: 150}}>One</div> <div className="item" style={{flexBasis: 150, flexGrow: 2 }}>Two</div> <div className="item" style={{flexBasis: 100, flexGrow: 3 }}>Three</div> </div> <style jsx>{` .flex { display: flex; width: 800px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; box-sizing: border-box; } `}</style> </> ) }
解析:
計算剩餘自由空間
100px(flex-basis) + 10px(margin-right)
= 110px800px - 110px - 150px - 150px
= 390px,即存在正剩餘空間。計算各個flex子元素增加尺寸
1 + 2 + 3
= 6,即大於1 ,一個蛋糕不夠分,只能按照比例分了。。390px * 1 / Max(1, 6)
= 390px * 1/6
=65px100px + 65px
= 165px,大於其max-width=150px
指定的最大值,因此最終元素one的尺寸是150px。即元素one吃不完分配的蛋糕,把吃不完的蛋糕還回去了,讓其餘兄弟多分些(先拋個問題:這些吃不完的蛋糕如何分配呢?)。元素two和元素three從新分配剩下是自由剩餘空間,即回到步驟1從新計算。
800px - 元素one佔領的尺寸(150px - 10px)
= 640px640px - 150px - 150px
= 340px2 + 3
= 5340px * 2 / Max(1, 5)
= 340px * 2 / 5
= 136px340px * 3 / Max(1, 5)
= 340px * 3 / 5
= 204pxmax-
屬性衝突時,即元素one吃不完的蛋糕會放入總蛋糕中,由後面的flex子元素從新分配。若是存在負自由空間(negative free space),則採用flex-basis + flex-shrink
組合計算Flex子元素在主軸上的比例。flex-shrink
取值表達了個flex子元素貢獻的願望:
flex-shrink: 0.2
表示但願分攤負自由空間的20%;flex-shrink: 1
表示但願分攤100%負自由空間(夠兄弟,其餘兄弟不用分攤);flex-shrink: 2
表示但願分攤200%負自由空間(分攤的態度很明確)。flex容器都感動哭了,但爲了照顧各個flex子元素的感覺,採用了一個「更合理」的分攤規則:
negative_free_space * Min(1, SUM(flex-shrink))
valid_negative_free_space * A / SUM_A
。計算的規則比上面的要複雜一些,不是簡單的切分negative-free-space。收縮量不只依賴flex-shrink,還依賴flex-basis。這樣作只是爲了「更合理」,即相同的flex-shrink狀況下,flex-basis越小的flex元素收縮的越慢(跟納稅同樣,收入越高交的越多)。
注意: 若是flex-shrink總和小於1,則表示部分負自由空間被分攤了(即有些尺寸沒有被收縮)。
function demo5() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexGrow: 1, marginRight: 10}}>One</div> <div className="item" style={{flexBasis: 150, flexGrow: 2, flexShrink: 2 }}>Two</div> </div> <style jsx>{` .flex { display: flex; width: 300px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; } `}</style> </> ) }
解析(過長跟flex-grow過程相似):
計算剩餘自由空間
100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right)
= 150px150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)
= 190px-40px * Min(1, 1 + 2)
= -40px計算各個flex子元素收縮尺寸
100px * 1 + 150px * 2
= 400px40px * 100px * 1 / 400px
= 10px,即最終寬度 = 100px - 10px
= 90px40px * 150px * 2 / 400px
= 30px,即最終寬度 = 150px - 30px
= 120pxfunction demo8() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexShrink: 0.2, marginRight: 10}}>One</div> <div className="item" style={{flexBasis: 150, flexShrink: 0.3 }}>Two</div> </div> <style jsx>{` .flex { display: flex; width: 300px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; } `}</style> </> ) }
flex子元素超出了flex容器。
解析:
計算剩餘自由空間
100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right)
= 150px150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)
= 190px300px - 150px - 190px
= -40px,即存在負剩餘空間。-40px * Min(1, 0.2 + 0.3)
= -40px * 0.5
= -20px計算各個flex子元素收縮尺寸
100px * 0.2 + 150px * 0.3
= 65px20px * 100px * 0.2 / 65px
= 6.15px,即最終寬度 = 100px - 6.15px
= 93.85px20px * 150px * 0.3 / 65px
= 13.85px,即最終寬度 = 150px - 13.85px
= 136.15pxbox-sizing =border-box
留意:元素one, twobox-sizing= border-box
function demo6() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexGrow: 1, marginRight: 10}}>One</div> <div className="item" style={{flexBasis: 150, flexGrow: 2, flexShrink: 2 }}>Two</div> </div> <style jsx>{` .flex { display: flex; width: 200px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; box-sizing: border-box; } `}</style> </> ) }
解析:
計算剩餘自由空間
100px(flex-basis) + 10px(margin-right)
= 110px150px(flex-basis)
= 150px200px - 110px - 150px
= -60px,即存在負剩餘空間。-60px * Min(1, 1 + 2)
= -60px計算各個flex子元素收縮尺寸
60px * 1 + 110px * 2
= 280px60px * 60px * 1 / 280px
= 12.86px,即最終寬度 = 60px - 12.86px
= 47.14px(不包含padding,border)60px * 110px * 2 / 280px
= 47.14px,即最終寬度 = 110px - 47.14px
= 62.86px(不包含padding,border)留意該栗子中:
min-width=60px
function demo7() { return ( <> <div className="flex"> <div className="item" style={{flexBasis: 100, flexShrink: 2, marginRight: 10, minWidth: 60}}>One</div> <div className="item" style={{flexBasis: 150, flexShrink: 2 }}>Two</div> <div className="item" style={{flexBasis: 100, flexShrink: 1 }}>Three</div> </div> <style jsx>{` .flex { display: flex; width: 300px; outline: 1px dashed red; } .item { padding: 10px; border: 10px solid #666666; } `}</style> </> ) }
解析:
計算剩餘自由空間
100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right)
= 150px150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)
= 190px100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)
= 140px300px - 150px - 190px - 140px
= -180px,即存在負剩餘空間。-180px * Min(1, 1 + 2 + 2)
= -180px計算各個flex子元素收縮尺寸
100px * 2 + 150px * 2 + 100px * 1
= 400pxmin-width=60px
,即最終寬度爲60px。即分配給元素one的稅負須要由其餘兄弟分攤了。元素two和元素three從新分配剩下是自由剩餘空間,即回到步驟1從新計算。
190px - 190px - 140px
= -140px,即元素two,three要總縮減140px。150px * 2 + 100px * 1
= 400px140px * 150 * 2 / 400px
= 105px,即最終寬度 = 150px - 105px = 45px140px * 100 / 400px
= 35px,即最終寬度 = 100px - 35px = 65pxmin-
屬性衝突時,即元素不能再收縮時,由後面的flex子元素從新分攤剩餘空間。min-
屬性指定最小尺寸時,每一個元素都存在最小尺寸的。