CSS - 弹性布局(flex)

目录

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

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

弹性布局

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

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

主轴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无法让浮动元素实现水平居中。

CSS - 弹性布局(flex)_第1张图片

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

CSS - 弹性布局(flex)_第2张图片

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

CSS - 弹性布局(flex)_第3张图片

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

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

弹性布局

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

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

CSS - 弹性布局(flex)_第4张图片

 CSS - 弹性布局(flex)_第5张图片

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

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

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

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

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

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

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

justify-content:flex-start

CSS - 弹性布局(flex)_第6张图片

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

justify-content:center

CSS - 弹性布局(flex)_第7张图片

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

justify-content:flex-end

CSS - 弹性布局(flex)_第8张图片

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

justify-content:space-around

CSS - 弹性布局(flex)_第9张图片

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

justify-content:space-between

CSS - 弹性布局(flex)_第10张图片

 flexitem元素之间间隔相等

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

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

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

CSS - 弹性布局(flex)_第11张图片

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

CSS - 弹性布局(flex)_第12张图片

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

CSS - 弹性布局(flex)_第13张图片

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

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

CSS - 弹性布局(flex)_第14张图片

主轴放置于侧轴起始位置 

CSS - 弹性布局(flex)_第15张图片

主轴放置于侧轴中间位置 

CSS - 弹性布局(flex)_第16张图片

主轴放置于侧轴结束位置 

CSS - 弹性布局(flex)_第17张图片

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

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

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

CSS - 弹性布局(flex)_第18张图片

CSS - 弹性布局(flex)_第19张图片

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

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

CSS - 弹性布局(flex)_第20张图片

CSS - 弹性布局(flex)_第21张图片

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

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

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

CSS - 弹性布局(flex)_第22张图片

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

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

CSS - 弹性布局(flex)_第23张图片

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

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

CSS - 弹性布局(flex)_第24张图片

多行对齐

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

CSS - 弹性布局(flex)_第25张图片

但是可以发现,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值在侧轴上对齐; 

CSS - 弹性布局(flex)_第26张图片

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

CSS - 弹性布局(flex)_第27张图片

CSS - 弹性布局(flex)_第28张图片CSS - 弹性布局(flex)_第29张图片

CSS - 弹性布局(flex)_第30张图片

CSS - 弹性布局(flex)_第31张图片

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;

CSS - 弹性布局(flex)_第32张图片

CSS - 弹性布局(flex)_第33张图片

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

CSS - 弹性布局(flex)_第34张图片

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

CSS - 弹性布局(flex)_第35张图片

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。

CSS - 弹性布局(flex)_第36张图片

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

CSS - 弹性布局(flex)_第37张图片

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

CSS - 弹性布局(flex)_第38张图片

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

CSS - 弹性布局(flex)_第39张图片

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

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

CSS - 弹性布局(flex)_第40张图片

每个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%

CSS - 弹性布局(flex)_第41张图片 CSS - 弹性布局(flex)_第42张图片

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

CSS - 弹性布局(flex)_第43张图片

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

CSS - 弹性布局(flex)_第44张图片

CSS - 弹性布局(flex)_第45张图片

 对于两个值的情况

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

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

CSS - 弹性布局(flex)_第46张图片

CSS - 弹性布局(flex)_第47张图片

对于三个值的情况

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

CSS - 弹性布局(flex)_第48张图片

align-self

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

align-self的值如下:

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

CSS - 弹性布局(flex)_第49张图片

CSS - 弹性布局(flex)_第50张图片

你可能感兴趣的:(css,css,flex,布局)