【CSS】深度学习Flex布局

481 阅读8分钟

【祖传开头】

第一! 我不叫喂!今天仍就是早起学习的废柴程序员!

第二!在此时此刻做自己认为值得的事情。

第三!早睡早起报平安!

正常布局 vs Flex布局

如果没有css,那么文档元素的排列通常都是遵寻HTML默认的布局方式。比如下方一段HTML:

<p>这是段落</p>
<div>
    <span>文本1</span>
    <span>文本2</span>
</div>

从这个简单的例子可以看出HTML默认布局有以下两个特点:

  • 文档元素遵守自上而下、自左而右的排列规则。
  • 块级元素默认垂直排列。内联元素会水平排列。

CSS中的一些属性就会改变的HTML默认的布局方式,去实现更复杂更灵活的布局。CSS改变布局方式的方法主要有以下几种:

  • 设置display属性
  • 设置浮动
  • 设置position属性

今天我们的主角FlexBox,就是通过设置display来更改元素默认的排列方式,然后向下影响子元素的排列方式。关于Flex的一些基础概念,比如容器等可以参考ryf老师的博客,此处不加赘述。

FlexBox布局相对与正常布局流有什么优势?

Flex容器可以定义子元素的排列方向

flex布局中有两个非常重要的概念,就是 【主轴】和【交叉轴】。通过flex-drection可以定义主轴是水平还是垂直的,以及它的延申方向。交叉轴则是垂直于主轴方向。因此,在flex布局中,主轴是可变的,在主轴上排列的子元素,它们的方向也是可变的。所以相较于正常的布局流,flex布局更加灵活。

flex-drection: row;

flex容器的主轴即是水平方向,从左向右排列。交叉轴则为垂直方向,从上到下排列。

flex-drection: column-reverse;

flex容器的主轴即是垂直方向,自下而上排列。交叉轴则为水平方向,从左到右排列。

控制子元素对于空间的利用

弹性布局最大的特色就是在任何尺寸的屏幕中,都可以更改容器和容器的元素的尺寸,去填充多余的空间以及处理溢出的空间。

具体怎么个弹法?

讲完弹性布局对比正常布局的一些优势,我们再来探究一下,flex布局的具体表现方式以及和一些属性的关联。而控制子元素对于容器空间的利用主要是这三个属性:flex-growflex-shrinkflex-basis

正负自由空间

首先我们来看两个概念:正向自由空间和负向自由空间,也可以简单的理解为容器中多余的空间和子元素超出容器宽度时的溢出空间。

  • 正向自由空间 = 容器内剩余空间
  • 负向自由空间 = 容器溢出空间

min-content && max-content

width的两个属性min-contentmax-content,是根据元素内容来获取最小固定尺寸最大固定尺寸

此处,要区别于autoauto是游览器通过计算来指定元素的默认宽度,比如不设置wdith属性的块级元素在,width属性的默认值就是auto,游览器进行计算分析后会默认给这个块级元素分配100%的相对宽度。

min-content

对于文本内容,会以最小单位进行分割,显示最长单词的长度。

max-content 文本不进行换行时,所占据的宽度。

这两个尺寸都是固定的值,而不是随着浏览器窗口的改变而改变。

了解了这些概念我们就可以继续深入flex子元素在主轴上是如何分配空间的。

flex-basis

首先是flex-basis, 这个属性为指定子元素的初始尺寸。当元素自身定义的尺寸,比如width:200px,那么flex-basis的初始值就是200px。但有些情况,元素并没有指定尺寸,也就是flex-basis的值为auto。那么这个时候max-content就会开始起作用,也就是说flex-basis的初始值就是这个元素的max-content。

然后,确定了flex-basis的初始值后,父容器就会在这个尺寸的基础上为子元素分配对应的空间。

flex-grow 【flex增长系数】

默认值: 0

这个属性决定了子元素如何对容器中多余的空间进行利用。反之,在容器没有多余空间时,这个属性也就没有作用了。

flex-shrink 【flex收缩系数】

默认值: 1

这个属性也决定了元素在容器空间不足的时候,自身需要缩减的尺寸去对应多少溢出空间。反之,在容器没有溢出空间时,这个属性也没有起作用。默认收缩,即使子元素的初始尺寸之和超过父容器,会使子元素进行收缩。

那么我们可以先简单的用以下两个步骤来描述flex布局分配空间的过程:

  • 第一步:确定每个子元素的初始尺寸
  • 第二步:以初始尺寸为基础,结合子元素设置的增长收缩系数再次分配空间

flex:[<'flex-grow'> <'flex-shrink'> <'flex-basis'> ]

默认值:0 1 auto。

上述三个属性的简写属性,常用的值有auto(1 1 0), none(0 0 auto),1(1, 1, 0)

举个栗子

html

<div class="contatiner">
    <div class="item">元素1内容</div>
    <div class="item">元素2内容内容</div>
    <div class="item">元素3内容内容内容</div>
</div>

css

// 简化样式
.contatiner {
    width: 500px;
    display: flex;
}
.item {
    // 即flex的默认值
    flex: 0 1 auto;
}

简单说明一下

w: 容器总宽度
w1: 元素1宽度 
w2: 元素2宽度
w3: 元素3宽度

场景1 :
w1 + w2 + w3 < w (即容器存在内剩余空间)
flex: 0 1 auto;

子元素默认获取的是max-content对应的固定宽度,w1 = 75, w2 = 107, w3 = 139(约等于)。

场景2:
w1 + w2 + w3 < w(即容器存在内剩余空间)
flex: 1 1 auto;

flex-grow的值为1,即在容器中有剩余空间时,将空间划分后分配给每个子元素。此处每个子元素的flex-grow的值相同,所以会对剩余空间进行均分。从上图可以看到三个子元素的宽度仍旧是w3 > w2 > w1。每个元素都增长了约容器剩余宽度的 1/3

flex-grow为1时,不是直接将父容器的总空间进行分割,而是对容器剩余空间进行分割,在元素初始空间的基础上,加上额外的分配空间。

场景3:
w1 + w2 + w3 > w(即容器存在溢出空间)
flex: 0 1 auto 默认收缩
width: 500px 减少至 250px

当把父元素的width设置为250px,上述例子中仍旧是w3 > w2 > w1。并且三个子元素减少的尺寸大约都相同。

场景4:
w1 + w2 + w3 > w(即容器存在溢出空间)
flex: 0 1 auto 默认收缩
width: 500px 减少至 180px

此时可以看到元素1在减少至min-content对应的尺寸就不会再进行压缩。这个就是flex在处理容器剩余空间和溢出空间时最大的不同,即防止元素的尺寸减少到0

场景5:
w1 + w2 + w3 > w(即容器存在溢出空间)
flex: 0 0 auto 不收缩
width: 200px

元素直接超出父容器。

场景6:
元素1:flex: 1 0 auto 可伸展不可收缩
元素2:flex:1 1 auto
元素3:flex:1 4 auto
width: 100px;

此时元素1设置为不收缩,w1始终大于等于max-content。而元素3设置的flex-shrink的值大于元素2,因此减少的尺寸比元素2更多。但是由于每个元素的min-content不同,即使元素3设置的值是元素2的4倍,减少的尺寸也不简单是4倍的关系。

其他使用场景

使用margin来自动填充间距

.contatiner {
    width: 500px;
    display: flex;
}
.item:first-child {
    margin: auto;
}

从图中可知,在主轴方向设置子元素margin的值为auto,会自动计算剩余空间,进行分配。通常通过space-around: justify-content;会对所有子元素设置边距。在只对个别元素设置边距的情况,就可以使用margin来进行处理。

动态文本长度下超出显示...

.contatiner {
    width: 500px;
    display: flex;
}
.item:first-child {
    flex: 1;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

垂直居中

.contatiner {
    width: 500px;
    display: flex;
    align-items: center;
    justify-content: center;
}

兼容写法

对于不兼容flex布局的游览器环境可以通过dispaly: inline-blockvertical-align来进行安全处理。防止在某些不支持flex布局的游览器环境,布局崩坏。而在支持flex布局的环境,这些属性也会被忽略。

.contatiner {
    display: flex;
}
.item {
	display: inline-block;
    vertical-align: top;
}

【祖传结尾】

有问题欢迎批评指正呀~