CSS - 弹性布局(flex)

傷城~ 2023-09-28 15:57 68阅读 0赞

目录

传统布局的不足之处:导航栏实现案例说明问题

关于单个、一行多个浮动元素的水平居中实现

弹性布局

弹性容器的主轴和侧轴概念

弹性容器的主轴对齐&侧轴对齐(一维布局特性说明)

主轴flexitem元素弹性宽高,以及换行/换列

多行对齐

flex-flow复合样式属性

flexbox样式总结

flexitem专有样式说明

flex-grow及按比扩容

flex-shrink及按权重比压缩

flex-basis

flex复合写法

order

align-self


传统布局的不足之处:导航栏实现案例说明问题

CSS - 定位布局_伏城之外的博客-CSDN博客

上一个章节定位布局的粘性定位小节中,实现工商银行导航栏时,我使用了ul li,并且由于li是块容器,所以不支持在同一行上排列。此时有两个传统方案可以让li在一行排列:

  • 将li转为行内块元素
  • 将li转为浮动元素

但是这两个方案都有缺点:

  • 行内块元素之间会产生因为代码空格或换行导致的间隙,我们可以通过去除代码中行内块之间的空格、换行,来消除行内块元素之间的空隙,但是此时代码可读性就变差了
  • 浮动元素间虽然紧密贴合,但是会脱标,导致父元素ul的宽高塌陷,虽然给父元素加overflow:hidden,将父元素ul变为BFC容器可以解决宽高塌陷,但是此时父元素的内容区宽度是占满一行的,这将导致无法让父元素紧密包裹子浮动元素,导致无法带子浮动元素水平居中

关于单个、一行多个浮动元素的水平居中实现

首先浮动元素脱标后,浮动元素在浮动流中是不会占满一行的(即不会通过margin来占满剩余宽度),所以此时margin:0 auto无法让浮动元素实现水平居中。

22944747e1b04336911fe52a5770a07b.png

此时我们可以给浮动元素包裹一个标准流父元素,并设置宽高为子浮动元素宽高,之后margin:0 auto父元素。

b6f076e7b81a4b86a4062bf5efded54b.png

这种方法也适用于一行多个浮动元素的水平居中

ab911713739f438999301d88b7b1932c.png

但是当浮动元素未设置宽高(即浮动元素宽高由其内容撑开)时,其标准流父元素的宽高设置将很难给定,而父元素宽高无法确定,则无法实现准确的父元素携带子浮动元素水平居中。

那么此时我们需要怎么办呢?

弹性布局

Flexible Box 模型,通常被称为 flexbox,是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布和对齐能力。

这里一维布局的意思指的是:flexbox的子元素只会按照行方向或者列方向,一个方向上进行布局。

当我们为一个元素添加display:flex样式后,该元素就变为了flexbox,即弹性容器。flexbox的子元素就变为了flexitem,即弹性项目。

弹性布局的弹性布局分别体现在:

  • 弹性:flexitem元素可以膨胀以填充额外的空间,收缩以适应更小的空间。
  • 布局:flexbox给予了flexitem强大的空间分布和对齐能力

弹性容器上支持如下样式属性:

  • flex-flow:flex-direction flex-wrap
  • justify-content
  • align-items
  • align-content

弹性项目上支持如下样式属性:

  • order
  • flex:flex-grow flex-shrink flex-basis
  • aligin-self

弹性容器的主轴和侧轴概念

我们知道弹性布局是一维布局,flexItem只会在flexbox的一个方向上进行布局,即flexbox的主轴方向。而flexbox的主轴的垂直方向就是flexbox的侧轴方向。

flexbox的主轴并非固定是水平方向或垂直方向,而是取决于flexbox元素的flex-direction样式,flex-direction属性值如下:

  • row(默认)
  • row-reverse
  • colum
  • colum-reverse

我们通过下图来理解这四个值得含义

0bf54501bf0e44ae9017f3bfe4c906c1.png

22a0d00a14bd45a28b997be4a36e2381.png

弹性容器的主轴对齐&侧轴对齐(一维布局特性说明)

其实理论上来说,弹性布局是一维布局,弹性容器中的弹性项目flexitem只能在主轴上进行各种对齐。而flexitem元素在主轴上的各种对齐就是主轴对齐。侧轴对齐并不是针对每个flexitem元素的,而是针对整个主轴的。所以flexitem元素只在主轴上布局,弹性布局是一维布局。

主轴对齐指的是:flexitem在flexbox主轴上的对齐方式

侧轴对齐指的是:整个主轴在侧轴上的位置

设置主轴上元素的对齐方式使用样式justify-content,它具有如下属性值:

  • flex-start(默认值)
  • center
  • flex-end
  • space-between
  • space-around

下面通过代码看看以上对齐效果:

justify-content:flex-start

520ab2625f1b49efb1bfaa7bffebd01c.png

flexitem元素从flexbox容器的主轴起始线排列

justify-content:center

6385febcd36648e99cc7c68b88592439.png

flexitem元素从flexbox容器的主轴中间排列

justify-content:flex-end

9473b6c265644a448645282011ada3ed.png

flexitem元素从flexbox容器的主轴终止线排列

justify-content:space-around

3a85faca47014c1c859212fccfc1fcaa.png

每个flexitem元素的左右空间相等

justify-content:space-between

7d0292602cb14d17b2ca62ba30c51d5b.png

flexitem元素之间间隔相等

设置整个主轴在侧轴上的位置用样式align-items,它具有如下属性值:

  • stretch(默认值)
  • flex-start
  • center
  • flex-end
  • baseline

下面通过代码看看以上属性值效果:

f57b95760459453ca4f77e489313edb9.png

align-items的默认值是stretch,含义是自动拉伸自适应高度的flexitem元素的高度为flexbox的高度

def2aa1c3dd5424cb872c9a1f6e399ab.png

对于设置高度height的flexitem元素而言,align-items不会拉伸其高度

68316ed49d874f8da589cf8cd855e8a7.png

如果flexbox也没有高度,则flexbox会被高度最高的flexitem元素撑开,即flexbox的高度为最高的flexitem元素的高度。

所以实际上,此时无高度的flexitem会默认被拉伸到最高的兄弟flexitem元素的高度

3f6567e391b645e6a4126bf9e27d7614.png

主轴放置于侧轴起始位置

4bde3eefb25d45c7b6778f7ab947a9f5.png

主轴放置于侧轴中间位置

f999ad243b5b4b709ced0af3221b5630.png

主轴放置于侧轴结束位置

4dfb2015245446e4ab62154643387952.png

主轴上flexitem元素按照内容文字的基线baseline对齐

主轴flexitem元素弹性宽高,以及换行/换列

当我们主轴上flexitem过多,以至于超出flexbox宽/高时,默认情况下,主轴上的flexitem元素是不会换行的,而是表现出flexitem元素的弹性宽/高特点,即flexitem元素的会被尽可能地压缩宽/高以适应flexbox的宽/高,但是一个flexitem元素的宽度最多被压缩到内容宽高,如果flexitem压缩到内容宽高还是超过flexbox宽高的话,则默认会超出flexbox范围,而不是换行。

019e6438b18c40d388b699a33e02c60d.png

3a29568b6c4d43f69b80df393072ec72.png

我们可以通过flexbox容器样式属性 flex-wrap 来控制主轴上flexitem是否换行,flex-wrap属性值如下:

  • nowrap(默认值)
  • wrap
  • wrap-reverse

86a2ee502ba74c9f97b24f09757c86f1.png

c21b712628ee470b8f9431d46089766e.png

当给flexbox设置flex-wrap:wrap后,此时主轴上flexitem元素的宽高不会再被压缩,当flexbox一行/一列放不下多余flexitem时,则对应flexitem换行或换列显示。

换行/换列时,如果flexbox在对应换行/换列方向上有剩余空间,默认情况下剩余空间会被均分,保证每个flex-item的在对应方向的边距相同。

但是如果我们设置了侧轴对齐方式,则

8c817141ad984a469ad6ed0af4b3c999.png

当flexbox设置了flex-wrap:wrap,即使主轴换行/换列也放不下多余的flexitem,flexitem也不会被被压缩宽高,而是超出flexbox范围。

flex-wrap:wrap-reverse是反向换行

801aae490858494cab21ab47b2f9cbb1.png

需要注意的是 flex-direction:xxx;flex-wrap:wrap-reverse 不等价于 flex-direction:xxx-reverse; flex-wrap:wrap;

原因是:flex-wrap控制的是换行/换列的方向,而不是主轴的方向

2a6ad86b88f246198dd25ba440bd9fcf.png

多行对齐

上例中,我们可以通过align-items来设置多行的在侧轴上的对齐方式

b6053610c8984c9880f38f8b9dc25df1.png

但是可以发现,align-items设置的多行对齐,行与行之间总是留有空隙。

如果我们想让多行之间没有空隙的实现在侧轴上对齐,则需要借助flexbox的align-content样式。

首先,需要点明的是,align-content只能用于多行侧轴对齐设置,即只能用于flex-wrap:wrap的flexbox。

align-content从名字上看,其实就是将每一行或每一列当成一个整体元素,在flexbox侧轴上排列(让他们像主轴上的flexitem一样实现对齐),align-content具有如下常用属性值:

  • normal(默认值)
  • flex-start
  • center
  • flex-end
  • baseline
  • space-around
  • space-between

当align-content为normal时,则多行根据align-items值在侧轴上对齐;

37525d987ea94f9e88ae899cfe139ec8.png

当align-content不是normal时,则多行根据lign-content值在侧轴上对齐;

0ff8431380494c61ab51ec1cec474340.png

3655bff011eb4663b5d278f43904636f.pngbdadce098029401c96a17b9db1c6754d.png

8c066be65e264806adb3d597b7742fd3.png

1a54e152eb11493c919f6901caa1277d.png

flex-flow复合样式属性

flex-direction和flex-wrap可以复合写成flex-flow样式;

flex-flow:flex-direction flex-wrap

由于flex-direction的默认值是row,flex-wrap的默认值是nowrap,所以flex的默认值是:

flex-flow:row nowrap;

a7bbbf01324c4067bccb85937d2a264d.png

03e9062bf4c54299a2b7daa675dcda55.png

flexbox样式总结

我们通过给flexbox设置flex-direction来控制其主轴方向,设置flex-wrap来设置其是否换行,二者可以复合写为flex-flow。

主轴上flexitem元素的对齐使用justify-content,主轴行在侧轴上的位置用align-items,对于主轴多行情况,还可以将每一行当成整体元素使用align-content使其在侧轴上实现对齐。

flexitem专有样式说明

flexitem即flexbox在主轴上的弹性项目元素,当我们设置flexbox不换行时,flexitem元素的宽/高会具有弹性,下面以主轴row方向来说明:

  • 当flexbox一行放不下所有flexitem元素,则所有flexitem的宽度会被自动压缩到可以适配一行宽度位置,但是最小只能压缩到flexitem的内容宽度。
  • 当align-items为stretch时,对于未设置高度的flexitem来说,其高度会被拉伸到flexbox的高度。

这里我们发现通过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。

flex-grow及按比扩容

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所分得的剩余宽度

f939496b06f847c58e118f4503ead30f.png

剩余宽度 = 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

flex-shrink及按权重比压缩

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压缩宽度

c3b5b45c272f4ac991df6480cd013de7.png

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

flex-basis

MDN官方对于flex-basis的解释是:flexitem在主轴方向上的初始大小。如果不使用box-sizing:border-box盒子模型的话,那么flex-basis指定的就是flexitem的内容区主尺寸。

如果一个flexitem元素既设置了flex-basis(非auto值),又设置了内容区主尺寸(即content-box的width、height),则flexitem的内容区尺寸以flex-basis的值为准。

flex-basis的取值如下:

  • auto(默认值)
  • 指定尺寸
  • content

flex-basis:auto的意思是“参照我的width/height属性”,即flexitem的内容区尺寸取决于width\height。

62346047e9c1468aa77bdd856cbbed70.png

flex-basis:content,意思是参照flexitem元素实际内容的尺寸

50430692721a4927a8ee789bce24d620.png

flex-basis:指定尺寸,意识是忽略flexitem的主尺寸width/height,以flex-basis指定的尺寸为准

d6b3eed2d4054828ad3dea15f18a4628.png

另外由于flex-basis会影响flexitem的主尺寸大小,所以会影响剩余宽度计算,压缩宽度计算,即会影响flex-grow,flex-shrink。

8c38608855534b569a83682f9a883282.png

剩余宽度 = 200 - 85 - 50 - 50 = 15px

blue扩容后宽度 = 50 + 15 = 65px

bd6e9b99450b44589364f4a3ccdd67a2.png

每个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复合写法

flex-grow、flex-shrink、flex-basis可以复合写成flex样式属性。

flex:flex-grow flex-shrink flex-basis

但是flex的用法多种多样,其支持一个值,两个值,三个值的情况

对于一个值的情况

如果值为非负数字,且无单位,则该值对应flex-grow,且此时flex-shrink:1,flex-basis为0%

2f87154c1f714593be88428f141a0c1b.png 1a0a662f46b0491aa8578958b3cea2ae.png

如果值为一个有单位的数字,则带单位的数字对应flex-basis的值,且此时flex-grow:1,flex-shrink:1

6d612e1485c04ad3b089c89e58daac0f.png

如果值为auto或content,则也对应flex-basis的值,且此时flex-grow:1,flex-shrink:1

71a5546c31084cd28664ce7d9a797ef3.png

75535dbad49f40cf96f912c6ce937cad.png

对于两个值的情况

此时第一个值必然对应flex-grow,则只能是非负数。

第二值可以是flex-shrink,比如为非负数时,也可以时flex-basis,比如为带单位的值,auto,content。

449251f2e86f4c9a915f9441b2006a16.png

a6c50d4644524d478c0650e091b8d189.png

对于三个值的情况

则必然对应 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

order

flexitem元素还支持设置order样式来定义自身排列顺序,order值越小越靠前,order值默认为0,所以设置了正数的order的lfexitem总是显示在未设置order的flexitem后面。order还支持负数,order为负数的flexitem总是最先显示,因为它小于默认的order:0。

8e1e55a83c9a4ec3a4422530d5329377.png

align-self

align-self用于给特定的flexitem进行侧轴对齐,其值基本与align-items值相同。并且flexitem的align-self会覆盖来自flexbox的align-items。

align-self的值如下:

  • flex-start
  • center
  • flex-end
  • baseline

8d805cfaa0064e449f7d2378fa7ef1e7.png

b0ae3fa3bb70462f826540d1bc081a26.png

发表评论

表情:
评论列表 (有 0 条评论,68人围观)

还没有评论,来说两句吧...

相关阅读

    相关 CSS - 弹性布局flex

    目录 传统布局的不足之处:导航栏实现案例说明问题 关于单个、一行多个浮动元素的水平居中实现 弹性布局 弹性容器的主轴和侧轴概念 弹性容器的主轴对齐&侧轴对齐(一维布局