flex 间距_聊一聊Flex布局

Flex布局目前对于前端来说已经是一个非常熟悉且常用的布局方案了。有了它,我们很大程度上就可以避免原来让人头秃的正常流布局带来的很多IFC(inline-formatting-context)问题。随着浏览器的支持性不断增强,基本上我们日常的业务开发中95%以上的布局都可以通过Flex轻松解决。

但是最近团队面试过程中,我却发现大部分同学对于Flex的理解并没有想象中的那么清晰深入,大部分都只是停留在会用一些基础布局的阶段。今天刚好在梳理CSS这块的知识体系,所以我就把这块重要的Flex布局再和大家深入浅出的重温一下。

Flex布局的原理

Flex布局的方式,其实一句话说明就是:通过主轴和交叉轴两条轴上的排布方式来控制布局

f2c204054623c756c961fe4e939b17a6.png

如图所示,我们通过设置主轴和交叉轴两个方向的排布方式进行组合,即可以完成各种各样的布局

justify-content

我们可以通过justify-content属性设置主轴的排布方式,他有以下几种排列方式:

  • flex-start
  • flex-end
  • center
  • space-around
  • space-between
  • space-evenly

借用阮一峰老师的图来形象的描述一下每一种布局

c41db02f9164f77e80ea91db06c3d2f7.png

图中少了一个space-evenly,其实就是flex-item之间每个间隔都一样的布局。

我们这里主要探讨一下space-betweenspace-aroundspace-evenly的区别。

首先,无论是space-betweenspace-around还是space-evenly他们的相邻两个item的间距总是一致的,唯一的不同点是首尾两个元素是如何对齐的。用一个形象的图片可以描述他们之间的差异。

space-between

bfb620bf582ead8e8ab73fef8a0bb352.png

space-between的排列方式首尾对齐,这也就意味着这个行的布局计算方式是:

行总宽度 = item的宽度 + 1间距 + item的宽度 + 1间距 + item的宽度

浏览器就会根据上面的公式

  1. 行总宽减去各个item的宽度
  2. 将剩余宽度平分赋值给间距

之后布局都是按照这种模式来计算,下面的我就直接列公式了,大家知道这个原理就好。

space-around

f6f77f2f43d059addf179b36c4fe7e78.png

space-around的排列方式是首尾各留一半间距,它的行计算方式是:

行总宽度 = 0.5间距 + item的宽度 + 1间距 + item的宽度 + 1间距 + item的宽度 + 0.5间距

同样的,浏览器就会根据上面的公式

  1. 行总宽减去各个item的宽度
  2. 将剩余宽度按照比例赋值给间距

space-evenly

8cb08eef28060bb61bc10c2bd9988313.png

space-evenly的排列方式是首位各留1间距,它的行计算方式是:

行总宽度 = 1间距 + item的宽度 + 1间距 + item的宽度 + 1间距 + item的宽度 + 1间距

和上面一样的,浏览器就会根据上面的公式

  1. 行总宽减去各个item的宽度
  2. 将剩余宽度按照比例赋值给间距

align-items

相比于主轴,我们交叉轴的排列方式就要简单许多,交叉轴可以通过align-items属性来进行控制,我们来看看align-items都有哪些排列方式

  • stretch
  • start
  • end
  • center
  • baseline

除了stretch是将元素的交叉轴上高度/宽度拉伸到与容器的高度/宽度,baseline是以文本基线对齐,其他的分别是顶头、顶尾和居中,大家最常用的也就是居中了

通过flex布局我们可以轻松的解决以往正常流垂直居中的难题

同样是借鉴阮老师的图

a1b3a31d5fd7e2d12e2cfe595b1e145a.png

大家可以通过mdn的例子查看每种布局的效果

align-self

我们刚刚说了justify-contentalign-items,大家可能会发现这样的排布无论是主轴还是交叉轴,他们内部每个item元素的在这个轴上的排列方式都是一致的。那我们如果需要单独定制要怎么办呢?

首先主轴,不行,因为主轴的对齐方式大家可以看到是根据行整体来进行分配的,并不能单独定制(试想一下一个space-around里面有一个flex-start怎么计算?不仅你蒙,浏览器也蒙)

但是交叉轴就不一样了,我们之前说的align-items其实本质上是为交叉轴上的每个元素赋予一个统一的对齐方式,但是元素可以通过align-self自己进行单独定制。它的值和align-items基本一致,大家知道这个概念就好了。

align-content

们刚才了解到了align-itemsalign-self,我们会发现为什么align-items会比justify-content少了诸如space-aroundspace-betweenspace-evenly这种属性呢?

原因其实是之前我们都是一行多列的布局,并且由于主轴与交叉轴的默认是行与列,所以我们并没有出现多列的场景。其实细心的同学可以发现我们的flex布局基本上可以分为三类

  • xxx-content:可应用在多行/多列时的规则,可以进行更加灵活的布局。
  • xxx-items: 可应用在一般单行/单列时的规则,虽然也可以用在多行/多列场景下,但是排版方式较为单一(因为单行/单列也用不到content拓展的那些排列方式
  • xxx-self: 可应用在单个元素上的排列方式

所以按照这个理解,当出现多行场景时flex-wrap: wrap,我们想对于交叉轴做一些类似于justify-content对主轴做的一些操作时,就可以通过设置align-content来进行布局了,其值可以参考justify-content

按照同样的理解,除了以上说的,我们应该还会有justify-itemsjustify-self。大家感兴趣的话可以自己去试试看,类比align-itemsalign-self

place

我们根据前面学习了解到了justify-contentalign-items分别设置主轴与交叉轴。其实当我们同时设置justifyalign时,还可以用一个简写属性place

{
  // 等同于justify-content: center和align-items: flex-start
  place-content: center flex-start;
  // 等同于justify-items: center和align-items: flex-start
  place-items: center flex-start;
  // 等同于justify-self: center和align-items: flex-start
  place-self: center flex-start;
}

flex

在弹性布局中,我们基本上就两点:布局弹性。我们之前说的都属于布局篇章的内容,接下来我们就重点讲讲弹性部分。这部分也是我发现大家都大致用过,但是又不了解细节的部分。

我们的Flex布局的Flex,意思就是收缩。这也是Flex布局的一大特点,你无需设定具体的宽度,只需要设定比例容器就可以自由的进行伸缩。我们常常使用flex属性来定义对应的比例,所以我们接下来就剖析一下flex属性

flex由三部分组成

  • flex-grow:容器的拉伸规则
  • flex-shrink:容器的收缩规则
  • flex-basis:容器基础尺寸

flex-grow

flex-grow指的是当剩余空间充足时,各容器的拉伸部分内容分配,我们找几个盒子100px*100px的盒子放入一个500px宽的容器中

496f6b5a00bd7e1db9bcfb46a79f143a.png

可以看到三个100px的盒子是无法撑满一个500px的容器的,我们可以设置flex-grow属性来设定让他们分配剩余空间撑满盒子

57efd670aacac70f62eb5c823c3e545a.png

我们分别设置了flex-grow的属性为1、2、1,可以看到原本100px宽的盒子分别被撑为了150px、200px、150px。

有人可能会问,150:200:150不是3:4:3吗,怎么不是我们设置的1:2:1呢?

原因是因为flex-grow分配的是剩余空间,在这个例子中,由于我们的三个盒子都是宽100px,所以剩余空间就只剩下500 - 100 * 3 = 200px。我们按照指定的flex-grow分配这200px的结果是50px、100px、50px,最终将分配的剩余宽度加上原始宽度100px,就变成150px、200px和150px了

flex-grow默认值为0,也就是说默认的元素不会根据剩余空间进行拉伸。

flex-shrink

flex-grow是拉伸,与之对应的还有一个是收缩。flex-shrink就是负责收缩比例的。当无剩余空间同时放置各容器时,各容器的收缩规则就是由flex-shrink来进行定义的。

同样是刚才的三个盒子,我们现在把他们都变成200px的宽度。这样的话三个200px的盒子是无法放在一个500px的容器内的。

cc2d70d4d9a72297d1a77284f2277875.png
由于flex-shrink的默认值是1会自动收缩,所以为了展示放不下的效果,图中我们将flex-shrink设为0禁止收缩

这时我们可以设置flex-shrink属性,让他们根据比例进行收缩,同样设置为1:2:1的比例

7e592ccd9f747dde2b6d4dfca60d7ae8.png

flex-grow一样,flex-shrink也是分配超出的部分的缩减值

在我们这个例子中,三个200px的盒子宽为600px超出了500px容器100px的宽度。所以我们的flex-shrink就是按照比例来分配这100px宽度的。由于我们设置的flex-shrink属性为1:2:1,所以对应的我们缩放的尺寸就是25px、50px、25px,由于原盒子宽200px,最终我们的盒子宽为175px(200px - 25px)、150px(200px - 50px)、175px(200px - 25px)

当我们使用Flex布局并且把flex-shrink设置为0时,就可以轻松完成根据内部元素宽度排列一排的布局了,开源组件vue-awesome-swiper中就是使用的这种方式。

flex-basis

flex-basis指的是我们容器的基础尺寸,也就是在主轴上元素的初始值。值得一提的是它和width属性有着类似的作用,但是优先级却要高于width

flex

在实际项目中,我们一般都会使用flex属性这种简写的方式来代替单独声明flex-growflex-shrinkflex-basis。但是使用的时候还是有地方要注意的,比如说,当你设置flex: 1时,你知道代表的是什么吗?

flex可以指定三个值,但是有不同的赋值规则。当你设置flex:1时,其实代表的是flex-grow:1,而不是我们一般直觉中的同时设置flex-growflex-shrinkflex-basis三个值,所以flex-shrinkflex-basis其实还是默认的1和0

虽然flex的赋值规则比较复杂,但总的来说会根据指定数值是否有单位进行区分是flex-growflex-shrink还是flex-basisflex-grow的指定永远在flex-shrink之前。如果你想查看具体细节可以参考这里

值得一提的是当flex只有一个值赋值是会存在几个特殊的值:noneautoinitial

其中

flex: none // 等同于 flex: 0 0 auto
flex: auto // 等同于 flex: 1 1 auto
flex: initial // 等同于 flex: 0 1 auto

最后还有一点要说明的是,以上说的flex规则都是主轴部分的空间分配,当然你也可以通过flex-direction: column修改主轴。

基本上Flex布局部分的内容就在这里了,掌握了这些相信你可以轻松的应对大多数的布局问题了~

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值