今天小编跟大家讲解下有关控制Flex子元素在主轴上的比例的方法 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关控制Flex子元素在主轴上的比例的方法 的相关资料,希望小伙伴们看了有所帮助。
背景
flex布局更有效的实现对齐 空间分配。最近又学习下flex子元素的尺寸计算规则 主要是flex-grow, flex-shrink的计算规则的学习。
一、基本概念
1.1 主轴(Main axis)
定义了flex元素布局起始点和方向 flex子元素在主轴上依次放置。
主轴有4个方向 通过flex-direction指定:
row水平方向 从左到右 默认的
row-reverse水平方向 从右到左
column垂直方向 从上到下
column-reverse垂直方向 从下到上
1.2 主轴的尺寸(Main axis size)
就是flex容器content矩形(不包含padding, border, margin区域)在主轴方向的尺寸。
1.3 交叉轴(Cross axis)
交叉轴就是跟主轴锤子的方向 主要用于flex元素的对齐。
1.4 交叉轴的尺寸(Cross axis size)
就是flex容器content矩形(不包含padding, border, margin区域)在Cross轴方向的尺寸。
1.5 flex盒模型(flex box)
display为flex inline-flex 的元素 也叫flex容器。
1. flex容器包含的不仅是flex元素 也包含空白空间。
2. 涉及的CSSflex-directionflex-wrapflex-flow
flex-direction flex-wrap flex-flowflex-direction和 flex-wrap的简写。
justify-content控制flex容器内容(flex元素和空白空间)在主轴方向对齐。注意区分align-items。
align-content控制多行flex容器个行的对齐方式。
align-items控制flex容器内容(flex元素和空白空间)在交叉轴方向对齐。
Tip:
1、这些CSS属性都是有相关性的:
首页先指定flex容器的主轴方向(flex-direction), 如果flex子元素超过在主轴 尺寸 那就涉及是否换行(flex-wrap)。如果没有超过主轴尺寸 那就涉及行内对齐(justify-content), 如果存在多行每个行直接也要对齐(align-content)。
2、可能比较容易混淆 justify-content align-content align-items。
记住content是指flex元素和空白空间 items指的是flex元素。这样就容易就是这三个属性的用处了。
1.6 flex元素(flex items)
1. 语法
flex box的子元素 不包含流外子元素( absolute, fix元素) 但是包含float元素。
flex子元素相邻的margin不会发生合并。
float元素作为flex子元素时 float属性无效(因为要参与flex布局 不是流式布局)。
2. 涉及CSS属性
flex-basis指定flex元素在主轴方向上占用flex容器的尺寸 默认为auto 即以flex元素的尺寸作为其占用的尺寸(主轴是row取值flex元素的宽度 主轴是column取值flex元素的高度) 根据该属性计算是否有空余空间。
注意:flex元素占用的尺寸跟flex-basis有关 跟元素的宽高没直接关系。
flex-grow指定各个flex元素弹性增长因数 即占用正空白空间(positive free space)的比例份额数量。0值(默认值)表示不占用空白空间
flex-shrink指定各个flex元素弹性收缩因数 即分配负空白空间(negative free space)的比例份额数量。但是元素不能无限收缩为0 也不能小于元素的最小尺寸(如min-width或者min-height)。
flexflex-grow flex-shrink flex-basis简写
align-self调整自己在交叉轴的对齐方式 只有在不撑满交叉轴时 这个属性才有效。
order指定顺序
二、计算自由空间和flex-basis
flex子元素在主轴上的比例依赖这三个CSS属性:
flex-basis flex-grow flex-shrink其中:flex-basis + flex-grow组合控制着伸flex-basis + flex-shrink组合控制着缩所以要确定flex子元素在主轴上的比例 首先要确定使用哪种组合。
2.1 规则
flex-basis 属性指定在任何空间分配发生之前初始化flex子元素的尺寸 更确切的说flex-basis 属性指的flex子元素盒模型(box-sizing)的尺寸 所以跟flex子元素width(height)取值逻辑类似 如果box-sizing=content 则flex-basis也不包含padding和border区域。
2.2 剩余自由空间计算
自由空间计算flex容器在主轴方向的content矩形的尺寸
期望自用空间在计算flex容器的自由空间前要先统计flex子元素占用的尺寸 注意这里指的是flex子元素的margin区域的尺寸 并且相邻的flex子元素margin是不会发生合并的。
剩余自由空间计算 = 自由空间计算 - 期望自用空间
正自由空间正值的剩余自由空间 此时采用flex-basis + flex-grow组合。
负自由空间负正值的剩余自由空间 此时采用flex-basis + flex-shrink组合。
三、深入了解flex-grow
3.1 规则
如果存在正自由空间(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子元素的flex-grow得出总和 简称SUM_flex_grow; 如果SUM_flex_grow=0 则不发生弹性增长 结束; flex子元素增长的尺寸 = 正自由空间尺寸 * flex_grow / Max(SUM_flex_grow, 1)。3.2 Demo1:按照比例分蛋糕
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> </> )}解析:
计算剩余自由空间
flex容器主轴尺寸 = 600px 元素one的希望尺寸 = 100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right) = 150px 元素two的希望尺寸 = 150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) = 190px 剩余自由空间 = 600px - 150px - 190px = 260px 即存在正剩余空间。计算各个flex子元素增长尺寸
SUM_flex_grow = 1 + 2 = 3 即大于1 一个蛋糕不够分 只能按照比例分了。 元素one的实际增长尺寸 = 260px * 1 / Max(1, 1 + 2) = 260px * 1 / (1 + 2) = 86.67px 元素two的实际增长尺寸 = 260px * 2 / Max(1, 1 + 2) = 260px * 2 / (1 + 2) = 173.33px3.3 Demo2:SUM(flex-grow) < 1
function 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> </> )}解析:
计算剩余自由空间
flex容器主轴尺寸 = 600px 元素one的希望尺寸 = 100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right) = 150px 元素two的希望尺寸 = 150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) = 190px 剩余自由空间 = 600px - 150px - 190px = 260px 即存在正剩余空间。计算各个flex子元素增长尺寸
SUM_flex_grow = 0.2 + 0.3 = 0.5 即小于1 一个蛋糕能满足大家需求 直接分给各个flex子元素。 元素one的实际增长尺寸 = 260px * 0.2 / Max(1, 0.5) = 260px * 0.2 = 52px 元素two的实际增长尺寸 = 260px * 0.3 / Max(1, 0.5) = 260px * 0.3 = 78px注意:
如果SUM(flex-grow)小于1 此时剩余空间没有全部分配给各个flex子元素。
3.3 Demo3 跟max-width冲突
留意该栗子中:
元素one, two, threebox-sizing=border-box 元素one的max-width=150pxfunction 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> </> )}解析:
计算剩余自由空间
flex容器主轴尺寸 = 800px
元素one的希望尺寸 = 100px(flex-basis) + 10px(margin-right) = 110pxbox-sizing=border-box
元素two的希望尺寸 = 150px(flex-basis) = 150pxbox-sizing=border-box
元素three的希望尺寸 = 150px(flex-basis) = 150pxbox-sizing=border-box
剩余自由空间 = 800px - 110px - 150px - 150px = 390px 即存在正剩余空间。
计算各个flex子元素增长尺寸
SUM_flex_grow = 1 + 2 + 3 = 6 即大于1 一个蛋糕不够分 只能按照比例分了。。 元素one的增长尺寸 = 390px * 1 / Max(1, 6) = 390px * 1/6 =65px这样元素one的尺寸就是100px + 65px = 165px 大于其max-width=150px指定的最大值 所以最终元素one的尺寸是150px。即元素one吃不完分配的蛋糕 把吃不完的蛋糕还回去了 让其他兄弟多分些(先抛个问题:这些吃不完的蛋糕如何分配呢 )。
元素two和元素three重新分配剩下是自由剩余空间 即回到步骤1重新计算。
flex容器主轴尺寸 =800px - 元素one占领的尺寸(150px - 10px) = 640px 剩余空间 = 640px - 150px - 150px = 340px SUM_flex_grow = 2 + 3 = 5 元素two的增长尺寸 = 340px * 2 / Max(1, 5) = 340px * 2 / 5 = 136px 元素three的增长尺寸 = 340px * 3 / Max(1, 5) = 340px * 3 / 5 = 204px3.4 小结:
计算剩余自由空间永远是第一步; 增长是个绝对值 即flex子元素会增加个绝对值(这是跟flex-shrink不同的地方); 当遇到max-属性冲突时 即元素one吃不完的蛋糕会放入总蛋糕中 由后面的flex子元素重新分配。四、深入了解flex-shrink
4.1 规则
如果存在负自由空间(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子元素的感受 采用了一个“更合理”的分摊规则:
计算flex子元素的content矩形(内容矩形)在主轴尺寸 和 flex-shrink乘积值 记作A; 累加步骤1的乘积值 记作SUM_A; 被分摊的负自由空间 valid_negative_free_space = negative_free_space * Min(1, SUM(flex-shrink)) 每个flex子元素的收缩值 = valid_negative_free_space * A / SUM_A。计算的规则比上面的要复杂一些 不是简单的切分negative-free-space。收缩量不仅依赖flex-shrink,还依赖flex-basis。这样做只是为了“更合理” 即相同的flex-shrink情况下 flex-basis越小的flex元素收缩的越慢(跟纳税一样 收入越高交的越多)。
注意: 如果flex-shrink总和小于1 则表示部分负自由空间被分摊了(即有些尺寸没有被收缩)。
4.2 Demo1:“减少贫富差距”
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过程类似):
计算剩余自由空间
flex容器主轴尺寸 = 300px 元素one的希望尺寸 = 100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right) = 150px 元素two的希望尺寸 = 150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) = 190px 剩余自由空间 = 300px - 150px - 190px = -40px 即存在负剩余空间。 被分摊的负剩余空间 = -40px * Min(1, 1 + 2) = -40px计算各个flex子元素收缩尺寸
SUM_A = 100px * 1 + 150px * 2 = 400px 元素one的实际收缩尺寸 = 40px * 100px * 1 / 400px= 10px 即最终宽度 = 100px - 10px = 90px 元素two的实际收缩尺寸 = 40px * 150px * 2 / 400px = 30px 即最终宽度 = 150px - 30px = 120px4.2 Demo: SUM(flex-shrink) < 1
function 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容器。
解析:
计算剩余自由空间
flex容器主轴尺寸 = 300px 元素one的希望尺寸 = 100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right) = 150px 元素two的希望尺寸 = 150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) = 190px 剩余自由空间 = 300px - 150px - 190px = -40px 即存在负剩余空间。 有效负剩余空间 = -40px * Min(1, 0.2 + 0.3) = -40px * 0.5 = -20px计算各个flex子元素收缩尺寸
SUM_A = 100px * 0.2 + 150px * 0.3 = 65px 元素one的实际收缩尺寸 = 20px * 100px * 0.2 / 65px= 6.15px 即最终宽度 = 100px - 6.15px = 93.85px 元素two的实际收缩尺寸 = 20px * 150px * 0.3 / 65px= 13.85px 即最终宽度 = 150px - 13.85px = 136.15px4.4 Demo3: box-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> </> )}解析:
计算剩余自由空间
flex容器主轴尺寸 = 200px 元素one的希望尺寸 = 100px(flex-basis) + 10px(margin-right) = 110px 元素two的希望尺寸 = 150px(flex-basis) = 150px 剩余自由空间 = 200px - 110px - 150px = -60px 即存在负剩余空间。 被分摊的负剩余空间 = -60px * Min(1, 1 + 2) = -60px计算各个flex子元素收缩尺寸
SUM_A = 60px * 1 + 110px * 2 = 280px 注意:此时不是直接用flex-basis去乘flex-shrink。本质上是使用flex子元素的content矩形宽度值去乘flex-shrink。 元素one的实际收缩尺寸 = 60px * 60px * 1 / 280px = 12.86px 即最终宽度 = 60px - 12.86px = 47.14px(不包含padding,border) 元素two的实际增长尺寸 = 60px * 110px * 2 / 280px = 47.14px 即最终宽度 = 110px - 47.14px = 62.86px(不包含padding,border)4.5 Demo5 跟min-width冲突
留意该栗子中:
元素one的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> </> )}解析:
计算剩余自由空间
flex容器主轴尺寸 = 300px 元素one的希望尺寸 = 100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) + 10px(margin-right) = 150px 元素two的希望尺寸 = 150px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right)= 190px 元素three的希望尺寸 = 100px(flex-basis) + 20px(padding-left/right) + 20px(border-left/right) = 140px 剩余自由空间 = 300px - 150px - 190px - 140px = -180px 即存在负剩余空间。 被分摊的负剩余空间 = -180px * Min(1, 1 + 2 + 2) = -180px计算各个flex子元素收缩尺寸
SUM_A = 100px * 2 + 150px * 2 + 100px * 1 = 400px 元素one的实际收缩尺寸 = 180px(负剩余空间的绝对值) 100px 2 / 700px = 51.43px 这样元素one的尺寸最100px - 51.43px = 48.57px 小于其min-width=60px,即最终宽度为60px。即分配给元素one的税负需要由其他兄弟分摊了。元素two和元素three重新分配剩下是自由剩余空间 即回到步骤1重新计算。
flex容器主轴尺寸 = 300px - 元素one占领的尺寸(60px + 20px + 20px + 10px) = 190px 剩余空间 = 190px - 190px - 140px = -140px 即元素two,three要总缩减140px。 SUM_A = 150px * 2 + 100px * 1 = 400px 元素two的收缩尺寸 = 140px * 150 * 2 / 400px = 105px 即最终宽度 = 150px - 105px = 45px 元素three的收缩尺寸 = 140px * 100 / 400px = 35px 即最终宽度 = 100px - 35px = 65px4.6 小结
缩减的规则稍稍复杂些 这背后是有原因的 主要防止宽度小的元素缩减太快导致为负宽度。 flex子元素发生弹性伸缩只是content矩形 其margin,border, padding不会发生弹性伸缩的 所以他们也不参与弹性伸缩的计算公式内(如弹性收缩的公式) 当遇到min-属性冲突时 即元素不能再收缩时 由后面的flex子元素重新分摊剩余空间。除了min-属性指定最小尺寸时 每个元素都存在最小尺寸的。参考
css-tricks: A Complete Guide to Flexbox规范Understanding flexbox
以上就是本文的全部内容 希望对大家的学习有所帮助 也希望大家多多支持爱蒂网。
来源:爱蒂网