一文掌握Flex布局不在话下

1,046 阅读7分钟

前言

由于Flex布局有更好的页面重排性能,并且只要学习几个CSS属性,就可以写出简洁、优雅的页面布局。因此,学习CSS布局首先精通Flex无疑是最佳的一种选择。

Flex基本概念

Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性,采用Flex布局的元素,称为Flex容器(flex container)。

在Flex容器中存在两条轴,默认设置是:水平主轴(main axis) 和垂直的交叉轴(cross axis)。我们可以通过修改使垂直方向变为主轴(main axis),水平方向变为交叉轴(cross axis)。

不能先入为主认为页面宽度就是水平主轴(main axis),高度就是垂直的交叉轴(cross axis),这个需要取决于当前页面主轴的方向,如果垂直方向是主轴,那么页面的高度就是main axis。

在flex容器中,每个单元块被称为flex item(项目),每个项目占据的主轴空间为main size,占据的交叉轴空间为cross size。

flex.png

Flex容器

实现 flex 布局需要先指定一个容器,任何一个容器都可以被指定为 flex 布局,这样容器内部的元素就可以使用 flex 来进行布局。如果你使用块元素如 div,你就可以使用 flex,而如果你使用行内元素,你可以使用 inline-flex。

.container {
  display: flex | inline-flex;
}

需要注意:当时设置容器为 flex 布局之后,每个单元块的 float、clear、vertical-align 的属性将会失效。

目前有下面六种属性可以设置在容器上,它们分别是:

  • 1.flex-direction
  • 2.flex-wrap
  • 3.flex-flow
  • 4.justify-content
  • 5.align-items
  • 6.align-content

1.flex-direction

决定主轴的方向(即项目的排列方向),有以下的取值

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}

flex-direction.png

2.flex-wrap

决定容器内项目是否可换行。默认情况下,flex-item都排在水平的主轴线上,有以下的取值

.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}

flex-wrap.png

3.flex-flow

flex-direction 和 flex-wrap 的简写形式,作用不是很大。平时写的话分开写就行,这样就不用记这个属性了。

.container {
  flex-flow: <flex-direction> || <flex-wrap>;
}



4.justify-content

定义了项目在主轴的对齐方式。有以下的取值

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

以下测试建立在主轴为水平方向,即flex-direction: row;。将以下图片往右旋转90度,那么即得到flex-direction: colum;的效果

justify-content-row.png

5.align-items

定义了项目在交叉轴上的对齐方式。有以下的取值

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

以下测试建立在主轴为水平方向,即flex-direction: row;

align-item.png

6.align-content

定义了多根轴线的对齐方式,如果项目只有一根轴线,那么该属性将不起作用。

比如:当flex-wrap设置为 nowrap 的时候,容器仅存在一根轴线,因为项目不会换行,就不会产生多条轴线;当flex-wrap 设置为 wrap 的时候,容器可能会出现多条轴线,这时候就可以去设置多条轴线之间的对齐方式了。有以下的取值

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

以下测试建立在主轴为水平方向,即flex-direction: row;flex-wrap: wrap;

align-content.png

Flex项目

目前有六种属性可运用在 flex-item 项目上:

  • 1.order
  • 2.flex-grow
  • 3.flex-shrink
  • 4.flex-basis
  • 5.flex
  • 6.align-self

1.order

定义项目在容器中的排列顺序,数值越小,排列越靠前,默认值为 0

.flex-item {
  order: <integer>;
}

在测试中,HTML结构里,虽然 -2,-1 的 item 排在后面,但是由于分别设置了 order,却能够排到最前面。

order.png

2.flex-grow

定义项目的放大比例,默认值为 0,即如果存在剩余空间,也不放大

.flex-item {
  flex-grow: <number>;
}

flex-grow.png

3.flex-shrink

定义了项目的缩小比例,默认值为 1。即如果空间不足,该项目将缩小;如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。负值对该属性无效

.flex-item {
  flex-shrink: <number>;
}

flex-shrink.png

4.flex-basis

定义了在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。默认值:auto,即项目本来的大小, 这时候 item 的宽高取决于 width 或 height 的值。

.flex-item {
  flex-basis: <length> | auto;
}

当主轴为水平方向的时候,当设置了 flex-basis,项目的宽度设置值会失效,flex-basis 需要跟 flex-grow 和 flex-shrink 配合使用才能发挥效果。

  • 当 flex-basis 值为 0 % 时,是把该项目视为零尺寸的,故即使声明该尺寸为 140px,也并没有什么用。
  • 当 flex-basis 值为 auto 时,则跟根据尺寸的设定值(假如为 100px),则这 100px 不会纳入剩余空间。

flex-basis.png

5.flex

flex-grow, flex-shrink 和 flex-basis的简写,flex 的默认值是以上三个属性值的组合。假设以上三个属性同样取默认值,则 flex 的默认值是 0 1 auto。建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值

.flex-item{
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
} 

flex特殊取值情况有如下几种:

/* 第1种 */
.flex-item {
  flex: auto;
}
.flex-item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: auto;
}

/* 第2种 */
.flex-item {
  flex: none;
}
.flex-item {
  flex-grow: 0;
  flex-shrink: 0;
  flex-basis: auto;
}

/* 第3种 */
.flex-item {
  flex: 1;
}
.flex-item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0%;
}

/* 第4种 */
.flex-item {
  flex: 0;
}
.flex-item {
  flex-grow: 0;
  flex-shrink: 1;
  flex-basis: 0%;
}

/* 第5种 */
.flex-item {
  flex: 0%;
}
.flex-item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0%;
}

/* 第6种 */
.flex-item {
  flex: 24px;
}
.flex-item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 24px;
}

/* 第7种 */
.flex-item {
  flex: 2 3;
}
.flex-item {
  flex-grow: 2;
  flex-shrink: 3;
  flex-basis: 0%;
}

/* 第8种 */
.flex-item {
  flex: 11 32px;
}
.flex-item {
  flex-grow: 11;
  flex-shrink: 1;
  flex-basis: 32px;
}



5.align-self

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

.flex-item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

这个跟 align-items 属性是一样的,只不过 align-self 是对单个项目生效的,而 align-items 则是对容器下的所有项目生效的。

align-self.png

补充说明

  • 1.当容器的flex-wrap 为 wrap | wrap-reverse,且每个项目宽度加起来的总宽度小于容器宽度时:flex-grow 会起作用,子项会根据 flex-grow 设定的值放大(值为0和负数的项目不放大)
  • 2.当容器flex-wrap 为 wrap | wrap-reverse,且每个项目宽度加起来的总宽度大于容器宽度时:首先一定会换行,换行后,每一行的右端都可能会有剩余空间,这时 flex-grow 会起作用,若当前行每个项目的 flex-grow 都为0,则剩余空间保留,若当前行存在一个项目的 flex-grow 不为0,则剩余空间会被 flex-grow 不为0的子项占据
  • 3.当容器flex-wrap 为 nowrap,且每个项目宽度加起来的总宽度小于容器宽度时:flex-grow 会起作用,项目会根据 flex-grow 设定的值放大(值为0和负数的项目不放大)
  • 4.当容器flex-wrap 为 nowrap,且每个项目宽度加起来的总宽度大于容器宽度时:flex-shrink 会起作用,项目会根据 flex-shrink 设定的值进行缩小(值为0和负数的项目不放大)。但这里有一个较为特殊情况,就是当这一行所有项目的 flex-shrink 都为0时,也就是说所有的项目都不能缩小,就会出现横向滚动条
  • 5.总结上面四点,可以看出不管在什么情况下,在同一时间,flex-shrink 和 flex-grow 只有一个能起作用,这其中的道理细想起来也很浅显:空间足够时,flex-grow 就有发挥的余地,而空间不足时,flex-shrink 就能起作用。当然,flex-wrap 的值为 wrap | wrap-reverse 时,表明可以换行,既然可以换行,一般情况下空间就总是足够的,flex-shrink 当然就不会起作用

辅助网站

1.Flex布局生成器:loading.io/flexbox/
2.Flex布局训练网站:flexboxfroggy.com/

参考文章

1.《Flex 布局语法教程》:www.runoob.com/w3cnote/fle…
2.《30 分钟学会 Flex 布局》:zhuanlan.zhihu.com/p/25303493