目录
传统布局的不足之处:导航栏实现案例说明问题
关于单个、一行多个浮动元素的水平居中实现
弹性布局
弹性容器的主轴和侧轴概念
弹性容器的主轴对齐&侧轴对齐(一维布局特性说明)
主轴flexitem元素弹性宽高,以及换行/换列
多行对齐
flex-flow复合样式属性
flexbox样式总结
flexitem专有样式说明
flex-grow及按比扩容
flex-shrink及按权重比压缩
flex-basis
flex复合写法
order
align-self
CSS - 定位布局_伏城之外的博客-CSDN博客
上一个章节定位布局的粘性定位小节中,实现工商银行导航栏时,我使用了ul li,并且由于li是块容器,所以不支持在同一行上排列。此时有两个传统方案可以让li在一行排列:
但是这两个方案都有缺点:
首先浮动元素脱标后,浮动元素在浮动流中是不会占满一行的(即不会通过margin来占满剩余宽度),所以此时margin:0 auto无法让浮动元素实现水平居中。
此时我们可以给浮动元素包裹一个标准流父元素,并设置宽高为子浮动元素宽高,之后margin:0 auto父元素。
这种方法也适用于一行多个浮动元素的水平居中
但是当浮动元素未设置宽高(即浮动元素宽高由其内容撑开)时,其标准流父元素的宽高设置将很难给定,而父元素宽高无法确定,则无法实现准确的父元素携带子浮动元素水平居中。
那么此时我们需要怎么办呢?
Flexible Box 模型,通常被称为 flexbox,是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布和对齐能力。
这里一维布局的意思指的是:flexbox的子元素只会按照行方向或者列方向,一个方向上进行布局。
当我们为一个元素添加display:flex样式后,该元素就变为了flexbox,即弹性容器。flexbox的子元素就变为了flexitem,即弹性项目。
弹性布局的弹性和布局分别体现在:
弹性容器上支持如下样式属性:
弹性项目上支持如下样式属性:
我们知道弹性布局是一维布局,flexItem只会在flexbox的一个方向上进行布局,即flexbox的主轴方向。而flexbox的主轴的垂直方向就是flexbox的侧轴方向。
flexbox的主轴并非固定是水平方向或垂直方向,而是取决于flexbox元素的flex-direction样式,flex-direction属性值如下:
我们通过下图来理解这四个值得含义
其实理论上来说,弹性布局是一维布局,弹性容器中的弹性项目flexitem只能在主轴上进行各种对齐。而flexitem元素在主轴上的各种对齐就是主轴对齐。侧轴对齐并不是针对每个flexitem元素的,而是针对整个主轴的。所以flexitem元素只在主轴上布局,弹性布局是一维布局。
主轴对齐指的是:flexitem在flexbox主轴上的对齐方式
侧轴对齐指的是:整个主轴在侧轴上的位置
设置主轴上元素的对齐方式使用样式justify-content,它具有如下属性值:
下面通过代码看看以上对齐效果:
justify-content:flex-start
flexitem元素从flexbox容器的主轴起始线排列
justify-content:center
flexitem元素从flexbox容器的主轴中间排列
justify-content:flex-end
flexitem元素从flexbox容器的主轴终止线排列
justify-content:space-around
每个flexitem元素的左右空间相等
justify-content:space-between
flexitem元素之间间隔相等
设置整个主轴在侧轴上的位置用样式align-items,它具有如下属性值:
下面通过代码看看以上属性值效果:
align-items的默认值是stretch,含义是自动拉伸自适应高度的flexitem元素的高度为flexbox的高度
对于设置高度height的flexitem元素而言,align-items不会拉伸其高度
如果flexbox也没有高度,则flexbox会被高度最高的flexitem元素撑开,即flexbox的高度为最高的flexitem元素的高度。
所以实际上,此时无高度的flexitem会默认被拉伸到最高的兄弟flexitem元素的高度
主轴放置于侧轴起始位置
主轴放置于侧轴中间位置
主轴放置于侧轴结束位置
主轴上flexitem元素按照内容文字的基线baseline对齐
当我们主轴上flexitem过多,以至于超出flexbox宽/高时,默认情况下,主轴上的flexitem元素是不会换行的,而是表现出flexitem元素的弹性宽/高特点,即flexitem元素的会被尽可能地压缩宽/高以适应flexbox的宽/高,但是一个flexitem元素的宽度最多被压缩到内容宽高,如果flexitem压缩到内容宽高还是超过flexbox宽高的话,则默认会超出flexbox范围,而不是换行。
我们可以通过flexbox容器样式属性 flex-wrap 来控制主轴上flexitem是否换行,flex-wrap属性值如下:
当给flexbox设置flex-wrap:wrap后,此时主轴上flexitem元素的宽高不会再被压缩,当flexbox一行/一列放不下多余flexitem时,则对应flexitem换行或换列显示。
换行/换列时,如果flexbox在对应换行/换列方向上有剩余空间,默认情况下剩余空间会被均分,保证每个flex-item的在对应方向的边距相同。
但是如果我们设置了侧轴对齐方式,则
当flexbox设置了flex-wrap:wrap,即使主轴换行/换列也放不下多余的flexitem,flexitem也不会被被压缩宽高,而是超出flexbox范围。
flex-wrap:wrap-reverse是反向换行
需要注意的是 flex-direction:xxx;flex-wrap:wrap-reverse 不等价于 flex-direction:xxx-reverse; flex-wrap:wrap;
原因是:flex-wrap控制的是换行/换列的方向,而不是主轴的方向
上例中,我们可以通过align-items来设置多行的在侧轴上的对齐方式
但是可以发现,align-items设置的多行对齐,行与行之间总是留有空隙。
如果我们想让多行之间没有空隙的实现在侧轴上对齐,则需要借助flexbox的align-content样式。
首先,需要点明的是,align-content只能用于多行侧轴对齐设置,即只能用于flex-wrap:wrap的flexbox。
align-content从名字上看,其实就是将每一行或每一列当成一个整体元素,在flexbox侧轴上排列(让他们像主轴上的flexitem一样实现对齐),align-content具有如下常用属性值:
当align-content为normal时,则多行根据align-items值在侧轴上对齐;
当align-content不是normal时,则多行根据lign-content值在侧轴上对齐;
flex-direction和flex-wrap可以复合写成flex-flow样式;
flex-flow:flex-direction flex-wrap
由于flex-direction的默认值是row,flex-wrap的默认值是nowrap,所以flex的默认值是:
flex-flow:row nowrap;
我们通过给flexbox设置flex-direction来控制其主轴方向,设置flex-wrap来设置其是否换行,二者可以复合写为flex-flow。
主轴上flexitem元素的对齐使用justify-content,主轴行在侧轴上的位置用align-items,对于主轴多行情况,还可以将每一行当成整体元素使用align-content使其在侧轴上实现对齐。
flexitem即flexbox在主轴上的弹性项目元素,当我们设置flexbox不换行时,flexitem元素的宽/高会具有弹性,下面以主轴row方向来说明:
这里我们发现通过flexbox样式来控制flexitem元素的弹性是普渡众生型的,所有flexitem元素都会被影响,如果我们想让部分flexitem的宽度不被压缩,则需要针对特定的flexitem元素进行设置,此时我们需要使用flexitem专有样式flex-grow,flex-shrink,flex-basis。
另外,flexbox只会按照代码顺序来排列flexitem,这是不自由的,所以我们需要使用flexitem专有样式order来针对每个flexitem元素设置排列顺序。
还有,flexbox是通过align-items来控制所有flexitem在侧轴上的对齐,也是普渡众生型的,为了能实现特定flexitem的侧轴对齐,我们可以使用align-self,该样式的值和align-items一致,但是只作用于特定flexitem,而不是所有flexitem。
MDN官方对于flex-grow的解释是:设置flexitem主尺寸的弹性增长系数。
flexitem的主尺寸指的是flexitem在主轴方向上的尺寸,
- 比如主轴为row或row-reverse时,flexitem的主尺寸就是宽度width;
- 比如主轴为colum或colum-reverse时,flexitem的主尺寸就是高度height;
弹性增长系数,其实就是当flexbox主轴方向存在剩余空间时,设置了flex-grow的flexitem主尺寸可以分配到的剩余空间的比例。
flex-grow可是任何非负数值,默认值为0。
flex-grow按比扩容计算规则:
假设:flexbox主轴方向是row,则
剩余宽度 = flexbox宽度 - 所有flexitem原始宽度之和
flexitem占比 = flexitem的flex-grow ÷ 所有flexitem的flex-grow之和
flexitem所分得的剩余宽度 = flexitem占比 × 剩余宽度
flexitem弹性宽度 = flexitem原始宽度 + flexitem所分得的剩余宽度
剩余宽度 = 500 - (100 + 150 + 50) = 200px
blue占比 = 0 / (0 + 1 + 1) = 0
red占比 = 1 / (0 + 1 + 1) = 1/2
orange占比 = 1 / (0 + 1 + 1) = 1/2
blue所分得剩余宽度 = 0 * 200 = 0
red所分得剩余宽度 = 1/2 * 200 = 100
orange所分得剩余宽度 = 1/2 * 200 = 100
blue未扩容
red扩容后弹性宽度为 150 + 100 = 250px
orange扩容后弹性看到为 50 + 100 = 150px
MDN官网对于flex-shrink的定义是: 该属性指定了flexitem的收缩规则。flexitem仅在默认宽度之和大于flexbox容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。
flexitem元素的flex-shrink值可以为任何非负数,默认值为1。
flex-shrink按权重比压缩计算规则:
假设:flexbox主轴方向是row,则
flexitem权重 = flexitem宽度 × flexitem的flex-shrink系数
总权重 = 所有flexitem的权重之和
flexitem权重比 = flexitem权重 ÷ 总权重
总压缩宽度 = 所有flexitem原始宽度之和 - flexbox宽度
flexitem压缩宽度 = flexitem权重比 × 总压缩宽度
flexitem弹性宽度 = flexitem原始宽度 - flexitem压缩宽度
flexitem的flex-shrink默认为1。
总权重 = (100 * 0 + 150 * 1 + 50 * 1) * 2 = 400
blue权重比 = 100 * 0 / 400 = 0
red权重比 = 150 * 1 / 400 = 3/8
orange权重比 = 50 * 1 / 400 = 1/8
总压缩宽度 = 600 - 500 = 100
blue压缩宽度 = 0 * 100 = 0
red压缩宽度 = 3/8 * 100 = 37.5
orange压缩宽度 = 1/8 * 100 = 12.5
blue未被压缩
red弹性宽度 = 150 - 37.5 = 112.5
orange弹性宽度 = 50 - 12.5 = 37.5
MDN官方对于flex-basis的解释是:flexitem在主轴方向上的初始大小。如果不使用box-sizing:border-box盒子模型的话,那么flex-basis指定的就是flexitem的内容区主尺寸。
如果一个flexitem元素既设置了flex-basis(非auto值),又设置了内容区主尺寸(即content-box的width、height),则flexitem的内容区尺寸以flex-basis的值为准。
flex-basis的取值如下:
flex-basis:auto的意思是“参照我的width/height属性”,即flexitem的内容区尺寸取决于width\height。
flex-basis:content,意思是参照flexitem元素实际内容的尺寸
flex-basis:指定尺寸,意识是忽略flexitem的主尺寸width/height,以flex-basis指定的尺寸为准
另外由于flex-basis会影响flexitem的主尺寸大小,所以会影响剩余宽度计算,压缩宽度计算,即会影响flex-grow,flex-shrink。
剩余宽度 = 200 - 85 - 50 - 50 = 15px
blue扩容后宽度 = 50 + 15 = 65px
每个flexitem的flex-shrink默认为1
压缩总宽度 = flexitem原始宽度之和 - flexbox宽度 = (85 + 50 + 50) * 2 - 200 = 170
总权重 = (85 * 1 + 50 * 1 + 50 * 1) * 2 = 370
red权重比为 85 * 1 / 370
blue权重比为 50 * 1 / 370
green权重比为 50 * 1 / 370
压缩宽度 = 压缩总宽度 * 权重比
则red弹性宽度为 = 原始宽度 - 压缩宽度 = 45.95px
flex-grow、flex-shrink、flex-basis可以复合写成flex样式属性。
flex:flex-grow flex-shrink flex-basis
但是flex的用法多种多样,其支持一个值,两个值,三个值的情况
对于一个值的情况
如果值为非负数字,且无单位,则该值对应flex-grow,且此时flex-shrink:1,flex-basis为0%
如果值为一个有单位的数字,则带单位的数字对应flex-basis的值,且此时flex-grow:1,flex-shrink:1
如果值为auto或content,则也对应flex-basis的值,且此时flex-grow:1,flex-shrink:1
对于两个值的情况
此时第一个值必然对应flex-grow,则只能是非负数。
第二值可以是flex-shrink,比如为非负数时,也可以时flex-basis,比如为带单位的值,auto,content。
对于三个值的情况
则必然对应 flex:flex-grow flex-shrink flex-basis
总结
flex | flex-grow (默认1) |
flex-shrink (默认1) |
flex-basis (默认0%) |
0 | 0 | 1 | 0% |
1 | 1 | 1 | 0% |
auto | 1 | 1 | auto |
content | 1 | 1 | content |
30px | 1 | 1 | 30px |
1 1 | 1 | 1 | 0% |
1 auto | 1 | 1 | auto |
1 1 auto | 1 | 1 | auto |
flexitem元素还支持设置order样式来定义自身排列顺序,order值越小越靠前,order值默认为0,所以设置了正数的order的lfexitem总是显示在未设置order的flexitem后面。order还支持负数,order为负数的flexitem总是最先显示,因为它小于默认的order:0。
align-self用于给特定的flexitem进行侧轴对齐,其值基本与align-items值相同。并且flexitem的align-self会覆盖来自flexbox的align-items。
align-self的值如下: