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-
属性指定最小尺寸时,每一个元素都存在最小尺寸的。