CSS – Flex 弹性布局详解
简介
Flex是Flexible Box 或 flexbox 的缩写 ,是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的布局方式。
弹性盒子由弹性容器(父元素)和弹性子元素(item)组成。
弹性容器(父元素)通过设置 display 属性的值为 flex 或 inline-flex 将其定义为弹性容器。
- 注意:inline-flex 不但把子元素变成块项目带伸缩功能,还会让弹性容器变成行内块元素
弹性容器(父元素)内包含了一个或多个弹性子元素
弹性容器(父元素)可以设置的属性有:
flex-direction
flex-wrap
flex-flow
justify-content
align-item
align-contnet
flex-direction 主轴方向
flex-direction 属性决定主轴的方向(即项目的排列方向)
其中包含4种排列方式: row(默认)
、row-reverse
、column
、column-reverse
它们的属性区别分别如下
row
: 主轴为水平方向,起点在左端,终点在右端,对应侧轴为垂直方向,起点在上方,终点在下方。
row-reverse
:主轴为水平方向,起点在右端,对应侧轴为垂直方向,起点在上方,终点在下方。
column
:主轴为垂直方向,起点在上方,终点在下方,对应侧轴为水平方向,起点在左方,终点在右方。
column-reverse
:主轴为垂直方向,起点在下方,终点在上方,对应侧轴为水平方向,起点在左方,终点在右方。
flex-wrap 换行方式
flex-wrap 默认情况下,项目都排在一条线(又称“轴线”)上。flex-wrap 属性定义,如果一条轴线排不下,如何换行的问题。
nowrap(默认)
: 不换行
wrap
:换行
wrap-reverse
: 反向换行
initial
:设置这个元素不受其它父元素样式影响
inherit
:继续父元素的样式
flex-flow 复合属性
flex-flow 其实就是 flex-direction 和 flex-wrap 的合集。
默认参数是 flex-flow : row wrap
一般比较少用。
justify-content 主轴对齐
justify-content 属性定义了项目在主轴上的对齐方式。
有5个参数可选:
flex-start(默认值)
: 左对齐
flex-end
: 右对齐
center
: 居中
space-between
: 两端对齐,项目之间的间隔都相等
space-around
: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍
space-evenly
: 每个项目的间隔相等。
align-items 单行侧轴对齐
align-items 属性定义项目在侧轴上如何对齐
共5个选项:
flex-start
: 元素置顶排列
flex-end
: 元素置底排列
center
: 元素居中
stretch
: 默认值,元素拉伸填充,前提是item没有设置高度。
baseline
: 元素基线排列(使用字母X来判断)
align-content 多行侧轴对齐
align-content 属性定义项目在多行情况下的侧轴上如何对齐
flex-start
:与侧轴的起点对齐。
flex-end
:与侧轴的终点对齐。
center
:与侧轴的中点对齐
space-between
:与侧轴两端对齐,中间平均分布。
space-around
:伸缩项目间的距离相等,比距边缘大一倍
space-evenly
: 在侧轴上完全平分。
stretch
:默认值,占满整个侧轴,前提是item没有设置高度。
flex-grow 盒子项目拉伸比
理解 flex-grow
在设置了flex-basis后,元素就占用了一定的空间。但还留有一些空间。这些空间可以通过flex-grow来占领。
以上面的这种情况为例,box1,box2,box3分别占据了父元素的15%,15%和20%的宽度,一共占据了50%宽度。还剩下50%的空白空间。
我们可以给box设置flex-grow属性。分别给三个box设置flex-grow:1。表示权重都是1,那么三个box将会平分剩下的空间。
.box1{
height: 150px;
flex-basis: 15%;
flex-grow: 1;
background-color: lightsalmon;
}
.box2{
height: 150px;
flex-basis: 15%;
flex-grow: 1;
background-color: lightgreen;
}
.box3{
height: 150px;
flex-basis: 20%;
flex-grow: 1;
background-color: lightblue;
}
父元素的宽度是1000px。
以box1为例,box1原来的宽度是1000*15%=150。grow的宽度是1000 * 50% * 1/3=500/3。
所以box1最终宽度是150+500/3。大家可以在开发者工具对比一下前后宽度就明白了。
如果子元素flex-grow的总和超过1,那么就是按照上面的方式,按比例(权重)瓜分剩下的空间。
还存在一种情况是flex-grow的总和没有超过1的,比如出现小数的情况。
.box1{
height: 150px;
flex-basis: 15%;
flex-grow: 0.3;
background-color: lightsalmon;
}
.box2{
height: 150px;
flex-basis: 15%;
flex-grow: 0.3;
background-color: lightgreen;
}
.box3{
height: 150px;
flex-basis: 20%;
flex-grow: 0.1;
background-color: lightblue;
}
这种情况就不会完全瓜分剩下的全部空间。而是子元素将自己的flex-grow值和剩余空间相乘,计算出的值就是增加的值。以box1为例,剩余空间是100050%=500,原来的宽度是10000.2=200,500*0.3=150这是增加的值,最后宽度是200+150=350。
和总和超过一的区别就是,不是按照各个子元素直接的权重比例来分配了,而是直接用flex-grow这个值乘以剩余空间来获取增长的值。
flex-grow的实际用途
其实上面提到的两种用法在实际开发中基本是用不上的。谁会给已经设置好宽度的元素又增加点宽度呢?实际上,下面这种用法才是最常见的。
下面这个效果在网页里面是经常用到的。左边是主要内容区,右边是一些小模块。使用flex-grow可以快速实现这样的功能。
我们想实现的效果是box1:box2=3,也就是box1宽度是box2宽度的3倍。
#content{
display: flex;
height: 700px;
font-size: 50px;
}
.box1{
height: 100%;
flex-grow: 3;
background-color: lightgreen;
}
.box2{
height: 100%;
flex-grow: 1;
background-color: lightblue;
}
<div id="content">
<div class="box1">box1</div>
<div class="box2">box2</div>
</div>
但实际上,如果你打开开发者工具,测量一下,box1和box2的宽度,你会发现两者比例根本不是3:1。这是为什么?
也许你一开始就看出我这样写是有问题的,那么恭喜你,你对flex理解的很深刻。原因出在你没有设置flex-basis=0上。注意,一定要设置为0,不写flex-basis默认值是auto。为什么设置flex-basis为0就可以了呢?
我们来分析一下上面的代码的执行逻辑:
上面的代码我们没有设置flex-basis,也没有设置width。flex-basis等于auto,width没有值。所以使用内容的宽度。 不信你把flex-grow属性都去掉,就会看到下面的效果。
这里引出flex-basis和width一个重要的区别。flex-basis默认值是auto,并且没有设置width的时候,flex-basis的值等于内容的宽度,值并不是为0的。这就是导致上面代码box1和box2不能实现3:1比例的原因。要想实现box1和box2比例是3:1,box1和box2的起始宽度必须是0。这样flex-grow就可以按比例平分父元素空间了。
只需要给两个box都加上flex-basis:0就可以实现按比例平分的效果了。
.box1{
height: 100%;
flex-grow: 3;
flex-basis: 0;
background-color: lightgreen;
}
.box2{
height: 100%;
flex-grow: 1;
flex-basis: 0;
background-color: lightblue;
}
flex-grow 属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
flex-grow: 0
如果所有项目的 flex-grow 属性都为1,则它们将等分剩余空间(如果有的话)。
如果一个项目的 flex-grow 属性为2,其他项目都为1,则前者占据的剩余空间将比其它项多一倍。
计算方法:
1.取出所有设置了 flex-grow 属性的值之和
2.按每个元素所设置的 flex-grow 属性的值取得对应比例的空间
flex-shrink 盒子项目压缩比
flex-shrink 属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
如果所有项目的 flex-shrink 属性都为1,当空间不足时,都将等比例缩小。如果一个项目的 flex-shrink 属性为0,其它项目都为1,则空间不足时,前者不缩小。
理解flex-shrink
有下面这样一个图。给三个元素设置flex-basis都等于40%。将会溢出一部分。
#content{
display: flex;
height: 500px;
width: 1000px;
background-color: lightpink;
font-size: 50px;
}
.box1{
height: 200px;
flex-basis: 40%;
background-color: lightgreen;
}
.box2{
height: 200px;
flex-basis: 40%;
background-color: lightblue;
}
.box3{
height: 200px;
flex-basis: 40%;
background-color: lightsalmon;
}
发现和想象中的不一样。box3并没有溢出。但三个flex-basis加起来确实是超出父元素宽度了。
但我心想,大牛写的书,应该不会骗我。一定是我写错了。但我没有写错,书里面说的也没错。
问题就出在flex-shrink身上。可是我也没写flex-shrink啊。你没写flex会自动给你添加上,而且默认值还不是0,而是1。
实际上,你上面的代码等价于下面的代码。
.box1{
height: 200px;
flex-basis: 40%;
flex-shrink: 1;
background-color: lightgreen;
}
.box2{
height: 200px;
flex-basis: 40%;
flex-shrink: 1;
background-color: lightblue;
}
.box3{
height: 200px;
flex-basis: 40%;
flex-shrink: 1;
background-color: lightsalmon;
}
flex-shrink的作用和flex-grow相反。当合计的flex-basis的总宽度超过父元素的总宽度的时候。flex-shrink会把子元素按比例减少,把溢出的宽度抹没。
比如前面的例子总宽度是40%*3=120%,也就是溢出了20%的宽度,也就是1000 * 20%=200px的宽度。怎么把这200px给抹没掉呢?就是从前面三个子元素上面扣宽度。三个子元素的flex-shrink都是1,也就是平均扣除200/3px。
就能实现抹没的效果。打开开发者工具,量一下子元素的宽度,确实是减少了这些宽度的。
如果说,我就想有这种溢出的效果,那么就把flex-shrink都设为0就好了。就可以达到下面这样效果。也就是书上提到的效果。
收缩比算法:
例如:
三个收缩项目,宽度分别为: 200px 、300px 、200px ,它们的flex-shrink 值分别为: 1 、2 、3
若想刚好容纳下三个项目,需要总宽度为700px ,但目前容器只有400px ,还差300px
所以每个人都要收缩一下才可以放下,具体收缩的值,这样计算:
1. 计算分母: (200×1) + (300×2) + (200×3) = 1400
2. 计算比例:
项目一: (200×1) / 1400 = 比例值1
项目二: (300×2) / 1400 = 比例值2
项目三: (200×3) / 1400 = 比例值3
3. 计算最终收缩大小:
项目一需要收缩: 比例值1 × 300
项目二需要收缩: 比例值2 × 300
项目三需要收缩: 比例值3 × 300
注意:收缩比会保证内容不被消失,因此项目收缩极限在于项目中的内容占用大小。
flex-basis 伸缩项目在主轴长的基准长度
flex-basis 属性定义了在分配多余空间之前,项目占据的主轴空间(main size).浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
若主轴是横向的则原先设定的宽width将失效,宽将为flex-basis的值,若主轴是纵向的则原先设定的高height失效,高将为flex-basis的值.
默认值:flex-basis : auto
,则浏览器采用伸缩项目的原宽或原高。
它可以设为跟 width 或 height 属性一样的值,则项目将占据固定空间。
理解 flex-basis
flex-basis这个属性是非常重要的一个属性,也是最容易混淆的一个属性。最开始以为和width属性差不多,也就没怎么重视。不弄清楚会造成和他相关属性的理解混乱。
其实flex-basis非常的好理解,你只需要逐字逐句的把他的定义理解一遍就行。
定义:
它的初始值是 auto,此时浏览器会检查元素是否设置了 width 属性值。如果有,则使用 width 的值作为 flex-basis 的值;如果没有,则用元素内容自身的大小。如果 flex-basis 的值不是 auto,width 属性会被忽略。
分为两种情况:
1.没有设置flex-basis,这时候flex-basis为默认值auto。
这种情况很常见,就是只设置了display:flex的时候。别的flex属性都没设置。此时浏览器会检查元素是否设置了 width 属性值。如果有,则使用 width 的值作为 flex-basis 的值;如果没有,则元素内容自身的大小。 这句话暗含了一个很重要的信息就是在flex里面,flex-basis是优先用于处理宽度的。更切确的说,在flex里面,根本不存在width,如果用户没设置flex-basis的值,flex系统会把width的值赋值给flex-basis。flex-basis有了值后,width被忽略,变成了工具人。
2.设置了flex-basis的值,这时候width会忽略,元素的宽度用flex-basis的值表示。
这点就更加验证了在flex里面,flex-basis是优先于width来处理宽度的。在flex里面只要用户设置了flex-basis的值,我flex系统都不正眼瞧你width。
总之,在设置了display:flex之后,你最好设置flex-basis的值,并且忽略width。 虽然width也是可以用,但就显得拖泥带水。就像你一只脚已经踏入我flex这个先进的布局系统里面,另一只脚还停留在原始的CSS里面。既然你已经用了flex这个系统,用就用全套,就用我flex-basis吧。而且我还可以和我另两个兄弟flex-grow 和 flex-shrink一起配合使用。组成flex三巨头。
虽然说flex-basis是替换了width,并且他和width起到的作用是差不多的。但他们还是不同的。当width为0的时候,我们是看不到元素的。但当flex-basis为0,或者为auto并且width没有设置值的时候(默认值为0),该元素的大小是由内容大小决定的。也就是只要有内容,flex-basis是不会看不到元素的。这在后面会从例子中体现。
设为auto和0也是有区别的。一个最明显的区别就是为0的时候,如果内容文字有空格是自动换行的。
这个可以通过设置white space:nowrap解决。auto就没有这个问题。
例一:
div1同时设置了width和 flex-basis,width的值将会失效。
.box1{
width: 150px;
height: 150px;
flex-basis: 200px;
background-color: lightsalmon;
}
.box2{
width: 150px;
height: 150px;
background-color: lightgreen;
}
.box3{
width: 150px;
height: 150px;
background-color: lightblue;
}
通常用法:
这里给父元素加了宽高和背景。
#content {
display: flex;
width: 1000px;
height: 500px;
background-color: lightpink;
}
.box1{
height: 150px;
flex-basis: 15%;
background-color: lightsalmon;
}
.box2{
height: 150px;
flex-basis: 15%;
background-color: lightgreen;
}
.box3{
height: 150px;
flex-basis: 20%;
background-color: lightblue;
}
flex 复合属性
flex 属性是 flex-grow(拉伸) , flex-shrink(收缩) 和 flex-basis(基准值) 的简写
语法:
flex: flex-grow flex-shrink flex-basis;
四个特殊简写值
flex: auto
flex: auto 即是 flex: 1 1 auto 的简写,代码如下:
/* 可以拉伸,可以压缩,基准值取原宽或原高 */
flex-grow: 1
flex-shrink: 1
flex-basis: auto
flex: 1
flex: 1 即是 flex: 1 1 0 的简写,代码如下:俗称->每个项目平均分配伸缩比例,且不受项目宽度大小(宽度被设为0以便让flex进行伸缩)
/* 可以拉伸,可以压缩,基准值取0,取消原高或原宽 */
flex-grow: 1
flex-shrink: 1
flex-basis: 0
flex: none
flex: none 即是 flex: 0 0 auto 的简写,代码如下:
/* 不可以拉伸,不可以压缩,基准值取原宽或原高 */
flex-grow: 0
flex-shrink: 0
flex-basis: auto
flex: 0 auto(默认值)
flex: 0 auto 即是 flex:0 1 auto 的简写,代码如下:
/* 不可以拉伸,可以压缩,基准值取原宽或原高 */
flex-grow: 0
flex-shrink: 1
flex-basis: auto
order 项目排序
order 属性定义项目的排列顺序。数值越小,排列越靠前(按轴方向的优选显示),默认为0 。
align-self 单独调整侧轴对齐
align-self 属性允许单个项目有与其它项目不一样的对齐方式,可覆盖 align-items 属性,默认为 auto , 表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch.
供 6 个参数可选择:
auto(默认值)
:继承了它的父元素 align-items 属性
stretch
:拉伸填充整个容器
center
:居中对齐
flex-start
:置顶对齐
flex-end
:置底对齐
baseline
:位于容器的基线上
align-content
align-content 属性是和 justify-content 相同的作用,只是 justify-content 是左右并排上的排列,而 align-content 是头尾上并排的排列。
提供 6 个选项
flex-start
:所有元素向顶堆叠
flex-end
:所有元素向底堆叠
center
:所有元素居中堆叠
stretch(默认值)
:向上堆叠,如果还有余空,不会平均分
space-between
:空间平均分,边框没有间隔
space-around
:空间平均分,但边框带有间隔
共有 0 条评论