Flex布局是 Flexible box
(弹性盒子)的缩写,因此常被称作“弹性布局”,它是对传统盒模型的补充和增强。在传统的盒模型中,布局盒子与子元素的关联性较弱,概念性地说,布局盒子只是为内部元素提供了布局边界。比如某个div内包含了3个左浮动的子元素(为了从视觉上区分三个子元素,我们设置了10像素的间距):
<style>
#container {
background-color: #F5F5D5;
}
.inner-element {
display: inline-block;
width: 100px;
height: 100px;
float: left;
margin-left: 20px;
background-color: #E64A19;
}
style>
<div id="container">
<div class="inner-element">内部元素1div>
<div class="inner-element">内部元素2div>
<div class="inner-element">内部元素3div>
<div style="clear: both;">div>
div>
而在实际开发中,一个很常见的需求是,让这3个元素自动填充盒子中剩余的空白,即下面的效果:
在传统的盒模型中,由于盒子只为子元素提供布局边界,而没有提供像剩余布局空间这样的信息,所以上面的效果只能通过复杂的js计算出来。而通过js来计算布局,不仅会增加js引擎的执行成本,还可能造成重绘甚至重排,影响网页性能。
传统盒模型中的布局盒子就像一道无形的屏障,内部元素只有“撞到”它的边界时,才知道它的存在。这种以子元素为布局实体的方式使得自适应布局很难实现。为此,我们需要一种更灵活的,能够为内部元素提供更多排列规则的布局方式。Flex布局就是这样一种新的布局方式。
Flex布局是从外部盒子的角度出发,来动态安置内部的子元素。在必要的情况下,它还可能对子元素进行一定的压缩或拉伸,以满足布局的需要。除了这些,Flex布局还会在盒子的大小发生变化时,重新计算内部子元素的布局,这是由CSS布局引擎自动完成的,所以性能非常高。此外,启用了Flex布局的盒子会自动生成一个BFC(Block formatting context,块格式化上下文),使得其内部布局的变化不会对外部造成影响,所以Flex布局得到了很广泛的应用。比如上面的布局,只需要以下几条样式声明即可(省略了背景颜色等非关键样式):
<style>
/* 定义弹性盒子 */
#container {
display: flex; /* 启用flex布局 */
jsutify-content: space-between; /* 自动分配空白 */
}
.inner-element {
width: 100px;
}
style>
Flex布局能实现的效果远不止这样,下面我们就来深入了解Flex布局。
首先我们先来理解Flex布局中一些重要的概念,它们是我们理解Flex布局的基础。
启用了Flex布局的元素称为Flex容器(Flex container),简称“容器”,它内部的每个直接子元素称为元素项(Flex item)。一个Flex布局描述的就是每个元素项在该容器内是如何放置的。以下是Flex布局示意图(图片来自阮一峰教程):
Flex布局内的各个元素项采用线性排列的方式。这里所说的线性,既可以是水平方向,也可以是垂直方向,两个方向都支持逆序排列。沿着元素项排列方向上的轴线我们称为主轴
(即main axis,注意,主轴既可能是水平方向,也可能是垂直方向);而主轴垂直方向上的轴线我们称为交叉轴
(即cross axis)。
主轴的开始位置我们称为main start
(即主轴起点);主轴的结束位置我们称为main end
(即主轴结束点);同样的,交叉轴的起点我们称为cross start
(交叉轴起点);交叉轴的终点我们称为cross end
(交叉轴结束点)。
容器内的每个元素项都有一定的宽高,它在主轴方向上所占的长度称为main size
;它在交叉轴上所占的长度则称为cross size
。默认情况下,元素项沿主轴方向排列,不会换行(排列不下时元素项可能会被压缩)。
以上概念对于理解和使用Flex布局非常重要,接下来我们来看Flex相关的语法。
Flex的语法规则分为两类,一类是应用于Flex容器,另一类是应用于Flex的元素项,下面分别介绍:
Flex容器支持6个属性:
flex-direction
,排列方向。flex-wrap
,换行方式。flex-flow
,以上两个属性的简写。justify-content
,元素项在主轴方向上的对齐方式,注意,主轴可能沿水平方向或竖直方向。align-items
,元素项在交叉轴方向上的对齐方式。align-content
,定义多条轴线的对齐方式。只有在允许换行的情况下才会存在多条轴线,如果只有一条轴线,则该属性不起作用。依次来看这6个属性:
定义元素项的排列方向,即主轴方向,可能有四个值:
row
(默认值),沿水平方向排列,从左到右。row-reverse
,沿水平方向逆序排列,从右到左。column
,沿垂直方向排列,从上到下。column-reverse
,沿垂直方向逆序排列,从下往上。定义元素项的换行方式,当元素项在一行内排列不下时生效。该属性有三个值:
nowrap
(默认),不换行。此时元素项会被压缩,以使其能排列在一行内。wrap
,换行。此时元素项会向下一行顺序排列。wrap-reverse
,换行并翻转行序。此时元素项会发生换行,但新的行在旧行的上面(或左面)。该属性是flex-direction
和flex-wrap
的简写,默认值是:flex-flow: row nowrap
。语法为:
.box {
flex-flow: || ;
}
定义元素项在主轴上的对齐方式。该属性支持5种对齐方式(假设主轴为从左到右):
flex-start
(默认),左对齐(即与main-start
对齐)。flex-end
,右对齐。center
,居中。space-between
,两端对齐,即空白只被分配到元素项之间,此时两端没有空白。space-around
,每个元素项两侧的间隔相等,此时元素项之间的间隙比两侧的间隙大一倍。space-between
和space-around
。space-between
的含义是空白位于元素项之间,这里有三个元素项,因此有两个间隙,它们会平分主轴上的剩余空间。space-around
的含义是空白位于元素项两侧,这里有三个元素项,因此需要将剩余空间平分为6份,这就不难理解,为什么元素项之间的间隙宽度是两侧宽度的2倍。定义元素项在交叉轴上的对齐方式。该属性也支持5种对齐方式:
flex-start
,与交叉轴的起点对齐。flex-end
,与交叉轴的终点对齐。center
,与交叉轴的中心对齐。baseline
,与元素项第一行文字的基线对齐。stretch
(默认),如果元素项未设置高度或设为auto,则元素项会占满整个高度。定义多根轴线的对齐方式,如果该项目只有一根轴线,那么该属性不起作用。该属性支持6个值:
flex-start
,与交叉轴的起点对齐。flex-end
,与交叉轴的终点对齐。center
,与交叉轴的中点对齐。space-between
,与交叉轴的两端对齐,轴线之间平分剩余间隔。space-around
,每根轴线两侧的间隔相等,同样的,轴线之间的间隔会比两侧大一倍。stretch
,轴线拉伸占满整个交叉轴。Flex元素支持6个属性:
order
,定义元素项的排列顺序。flex-grow
,定义元素项的放大比例。flex-shrink
,定义元素项的缩小比例。flex-basis
,定义在计算主轴剩余空间前,该元素项所占有的长度基准,默认auto,即元素项本身的长度。flex
,它是flex-grow
、flex-shrink
和flex-basis
三个属性的简写。align-self
,单独设置某个元素项的对齐方式,它用于覆盖容器上为每个元素项设置的align-items
属性。定义每个元素项的顺序,类型为整数(允许负数),元素项将按照order的值从小到大依次排列。默认情况下,每个元素项的order值都是0,所以会按书写顺序依次排列。例如:
<div style="display: flex;">
<div style="order: 1;">元素项1div>
<div style="order: 1;">元素项2div>
<div style="order: 0;">元素项3div>
div>
此时第三个元素项会被放置在最前面,而前两个由于order值相等,因此会接着按序排列。
定义元素项的放大比例,默认为0,即如果存在剩余空间,元素项也不会被放大。
当该属性的值不为0时,元素项将按与其他元素项的放大比例来分配剩余空间。
例如,现在有三个元素项,它们的flex-grow
均为1
。那么当容器内有剩余的空间时,三个元素项将分别得到1/(1+1+1)
,即三分之一的剩余空间,即,三个元素项会等分剩余空间。而假如三个值分别为1、2、1
,则第一个和第三个会分配1/(1+2+1)
,即四分之一的剩余空间,第二个元素会得到四分之二的剩余空间,所以它的放大比例是另外两者的2倍。很容易理解,当放大比例被设置为0时,该元素项不会被放大。
定义了元素项的缩小比例,默认为1,即如果空间不足,各个元素项将等比例缩小。如果某一项的值设置为0,则它不会被缩小。
整个缩小的计算过程是这样的:
如现在有4
个元素项,长度均为100像素
,而Flex容器的长度只有300像素
,并且flex-wrap
设置为不换行。显然,这四个元素项需要压缩后才能放进容器内。我们来计算需要压缩的长度值:
100px * 4 - 300px = 100px
即必须让四个元素项压缩总计100像素的长度时,它们才能被正确放进容器内。假设四个元素项的flex-shrink
均设置为1,那么它们将按1:1:1:1
的比例来分配这100像素,于是,最终每个元素项被压缩25像素
。同理,假如它们的flex-shrink
值分别为2、1、1、1
,则第一个元素项会被压缩40像素
,其他的被压缩20像素
(按照2:1:1:1
分配这100像素)。如果某一项被设置为0,则不会被压缩。
定义元素项所占的主轴空间大小。默认情况下,浏览器会根据元素项的实际宽高计算它占有主轴空间的长度,但是修改该值即可使元素占有固定的空间。
该值的默认值为auto
,即元素项本身的宽或高。把该值设置成如下值:
flex-basis: 200px;
可以使该元素项在主轴空间上始终占有200像素,而不管它的实际宽高。
它是flex-grow
、flex-shrink
和flex-basis
这三个属性的简写。三个属性的默认值分别为:0 1 auto
,即在空间剩余时默认不放大,空间不足时等比例缩小,并以其实际宽高计算所占主轴的空间。
用于为单个元素项设置交叉轴上的对齐方式。
容器的align-items
可以为每个元素项设置统一的交叉轴对齐方式,但是为某个元素项设置align-self
可以使其拥有与其他元素项不同的对齐方式,取值与align-items
是一致的。如:
.container {
display: flex;
align-items: flex-start;
}
#item3 {
align-self: flex-end;
}
本文主要是讲解了Flex布局的基本语法,关于Flex的应用,可以参考阮一峰老师的博客原文:Flex 布局教程:实例篇。