这次带大家彻底搞懂 flex 布局

109 阅读8分钟

本文首发于我的公众号:前端西瓜哥

大家好,我是前端西瓜哥,今天我来带大家彻底搞懂 flex 布局。

flex 布局,即弹性布局,是前端开发中非常常用的布局方式。主要是馋它很简单就能让容器内元素水平垂直居中的能力。

首先我们需要有一个容器元素(我们叫做 container),然后容器元素内有一些子元素(我们叫做 item)。

<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>

提供一些基本的样式。

.container {
  width400px;
  height150px;
  background-color: brown;
}

.item {
  border1px solid #333;
  border-radius8px;
  width50px;
  height50px;
  background-color: cornflowerblue;
}

这时候我们还没使用 flex 布局,它长这个样子:

图片

做水平居中

现在我们让上面的 item 元素,从左往右排列,并做一个水平居中。

首先我们启用 flex 布局,并设置主轴方向居中。

.container {
  display: flex;
  justify-content: center;
  /* ... */
}

效果为:

图片

盘点下用到的相关属性。

display

display 指定布局方式,这里用 flex,表示使用弹性布局。

flex-direction

flex-direction 指定弹性布局的主轴方向,即容器内 item 的排布方向。它的值有:

  • 默认值为 row(“行” 的意思),方向从左往右;

  • column(“列” 的意思),方向从上往下;

  • row-reverse(“行的反向” 的意思),方向从右往左;

  • column-reverse(“列的方向” 的意思),方向从下往上;

这里我没有设置改属性,所以默认是 row,item 从左往右排列。

justify-content

justify-content (“对齐内容” 的意思)指定 主轴方向 item 的对齐方式。常用的值有:

  • flex-start,默认值,对齐起始位置;

  • center,居中,我们经常使用它来实现居中布局;

  • flex-end,对齐末尾位置;

  • space-between,item 之间均匀加一些空间,但开头和末尾两个 item 的两边要向两侧靠齐;

  • space-around,类似 space-between,item 之间加一些间隔,包括头尾两个 item 的两边也留间隙;

图片

再做垂直居中

水平居中已完成,我们现在加个水平居中

.container {
  align-items: center;
  /* ... */
}

看看效果,此时可以看到我们的垂直水平居中就实现了。

图片

然后继续看相关的属性。

align-items

align-items (“对齐项” 的意思)对应 交叉轴的对齐方式。所谓交叉轴,指的就是和主轴垂直的轴线。比如对于我们的例子,主轴是从左往右,交叉轴就是上下方向。

align-items 常用的值有:

  • flex-start:对齐交叉轴起点位置。对于上下方向,对齐上边;对于左右方向,对齐左侧;

  • flex-end:对齐交叉轴终点位置;

  • center:居中对齐;

  • stretch:拉伸,在交叉轴的方向拉伸,当然前提是没有设置对应的固定宽或高;

  • baseline:对齐基线,比如有个 item 的字体相对比较大,基本就会下降,导致其他 item 下移。见下图

图片

align-self

align-items 是给所有的 item 应用相同的规则,如果有一些 item 想应用其他的对齐规则,也是可以的。

给对应的 item 使用 align-self 属性,值和 align-items 一样。默认值为 auto,继承自父元素的 align-items。

.item2 {
  align-self: flex-start;
}

这里我给第二个元素设置了 flex-start 对齐,渲染结果为:

图片

flex-wrap

当 item 元素很多的时候,我们需要设置换行规则,这个属性是加在容器元素上的。

flex-wrap 的属性值:

  1. nowrap,默认值,不换行。默认不换行的情况下,当 item 很多时,默认会被压缩。即使 item 设置了 width 也会被压缩,如果你不希望被压缩,可以使用 max-width,倒是会出现溢出的效果;

  2. wrap:换行,当位置不够时,自动换行;

  3. wrap-reverse:反向换行,第一行在最下面;

我们加多一些元素,然后设置换行:

.container {
 flex-wrap: wrap;
  /* 其他属性 */
}

效果为:

图片

align-content

当出现换行时,产生了多根轴线的。这些轴线可以通过 align-content 来设置对齐规则

如果只有一根轴线,此属性无效。

图片

align-content 支持的值和 justify-content 基本一致,它们分别对应不同的方向。只是默认值不同。

它的值有:

  • stretch,默认值,尽量拉伸填充满容器;

  • flex-start,对齐起始位置;

  • center,居中;

  • flex-end,对齐末尾位置;

  • space-between,item 之间均匀加一些空间,但开头和末尾两个 item 的两边要向两侧靠齐;

  • space-around,类似 space-between,item 之间加一些间隔,包括头尾两个 item 的两边也留间隙;

flex-flow

flex-flow 是 flex-direction 和 flex-wrap 的缩写属性。默认值为 row nowrap

flow 可以看作流向的意思,流向有两种方面,一种是流的方向,那就是 flex-direction;另一种则是流是否循环,那就是 flex-wrap。通过这种方式来思考不知道会不会更好记一些。

说真的,我觉得缩写属性是坏文明,像是一个有很多重载的函数,传入的参数五花八门,然后带来不同的效果。

缩写属性,给我们增加更多的学习成本,且容易写错,实在难受。当然一些常用的属性,我觉得可以用提供缩写属性,但参数形式也不应该太多。

order

指定某个 item 的顺序。是一个整数,值越小越靠前,越大越靠后。值可以是负数。对于相同 order,则按顺序排序。

我们将第二个 item 的 order 设小点,:

.item2 {
  order: -1;
}

效果:

图片

如果你想让一个第二个 item 跑到末尾,设置一个比 1 大的值即可。

order 可以实现不使用 JavaScript 就可以改变 item 的位置的效果,不过我实际开发中用的还是相当少。

flex-grow

flex-grow 用于设置 item 放大的权重。值为数字类型,可以为小数,但不能是负数。

item 可能没有占满整个容器,这时候可以用 flex-grow 指定一些元素,让它做一个放大,去占满整个容器。

flex-grow 默认值为 0,即有剩余空间也不放大。

我们给第 2、3 个 item 分别设置不同的 flex-grow

.item2 {
  flex-grow1;
}
.item3 {
  flex-grow2;
}

效果:

图片

该属性可以很方便地实现 “左侧宽度固定,右侧自适应” 的实现。

flex-shrink

flex-shrink 用于设置 item 缩小的权重。值为数字类型,可以为小数,但不能是负数。

容器存在有剩余空间的情况,自然也有空间不足的情况。对于空间不足的情况,flex 不希望 item 溢出,此时就会根据 flex-shrink 来分配不足空间的比例。

flex-shrink 默认为 1,即当空间不足时,所有的 item 都均摊相同的比例去做缩小。

经我测试发现,flex-shrink 缩小不能无限缩小的,还会被 item 内的内容撑大,所有是有一个适应内容宽度的最小值的。

如果你选择设置换行 flex-wrap: wrap 的话,那 flex-shrink 就没什么效果了,因为 item 不需要背缩小的绩效,不够位置换行就完事了。item 的宽度本身就已经超过容器宽度除外。

这次我们使用了 13 个 item,并给第二个元素设置 flex-shrink: 0,表示该元素不进行缩放,保持原来的宽度。

.item2 {
  flex-shrink0;
}

渲染结果为:

图片

flex-basis

flex-basis 用于指定分配剩余空间前 item 在主轴方向上的尺寸

主轴方向上的尺寸可能是 width,也可能是 height,为了方便描述,下面都默认为 width 的情况(主轴方向为水平)。

flex-basis 可以设置 width 一样的值。此外常见的关键字值有:

  • auto,默认值,item 的尺寸会使用 width,如果没有就根据 item 中的内容自适应(等价于值为 content),此外不能超出 min-width 和 max-width 的范围。

  • content,根据 item 中的内容宽度自适应。

如果 flex-basis 指定了具体的大小,flex-basis 的效果会覆盖 width。

将第 2 个 item 的宽度设置为内容自适应:

.item2 {
  flex-basis: content;
}

效果为:

图片

flex

flex 是 flex-grow,flex-shrink 和 flex-basis 的缩写属性。

支持的关键字值有:

  • auto,等价于  "1 1 auto",表示既会放大也会缩小;

  • none,等价于 "0 0 auto",表示既不会放大也不会缩小,保持 item 原来的尺寸;

此外还有常用的 "flex: 1",等价于 "flex: 1 1 0%"。最新标准应该是 "1 1 0px",但因为浏览器都已经实现了,为了兼容性考虑,浏览器厂商决定保持原样。

结尾

简单总结一下,我们首先给 container 元素设置 display: flex,然后就可以设置一堆的 flex 相关属性了。

然后,container 上的属性有:

  1. flex-direction:主轴方向,默认为从左到右(row);
  2. justify-content:主轴方向上 item 的对齐方式,常用 center 做居中;
  3. align-items:交叉轴方向上 item 的对象方式,配合 justify-content 就能做常用的水平垂直居中效果;
  4. flex-wrap:是否换行,默认是不换行的(no-wrap);
  5. align-content:交叉轴上轴线的对齐方式,出现换行的情况下才有用;
  6. flex-flow:flex-direction 和 flex-wrap 的缩写属性,评价为花里胡哨;

item 上的属性有:

  1. aligin-self:定义 item 自己在交叉轴上的对齐方式,默认值继承自父元素的 align-items;
  2. order:顺序,越小越靠前,默认值为 1;
  3. flex-grow:容器有剩余空间时,额外占据空间的尺寸权重;
  4. flex-shrink:容器空间不足时,缩小的尺寸权重;
  5. flex-basis:指定 item 的缩放前尺寸;
  6. flex:flex-growth、flex-shrink 和 flex-basis 的缩写属性;

我是前端西瓜哥,欢迎关注我,学习更多前端知识。