Contents
  1. 1. flex
    1. 1.1. flex-direction
    2. 1.2. flex-wrap
    3. 1.3. flex-flow
    4. 1.4. order顺序
    5. 1.5. 圣杯布局
      1. 1.5.1. flex方式
      2. 1.5.2. 传统方式
  2. 2. flex:auto
  3. 3. flex
    1. 3.1. flex-grow
  4. 4. flex
    1. 4.1. flex-grow
    2. 4.2. flex-shrink
    3. 4.3. flex-basis
  5. 5. 对齐
    1. 5.1. justify-content
    2. 5.2. 侧轴对齐
      1. 5.2.1. align-items
      2. 5.2.2. align-self
  6. 6. flex的baseline

Flexbox —— 全能快速弹性布局方式

没有接触过flex的同学,请查看w3官方文档中文版点这里)。
本文学习自该文档,是该文档的一份帮助学习博文

首先,flex出现之前,布局方式是怎么样的呢
CSS 2.1 定义了四种布局模式 - 由一个盒与其兄弟、祖先盒的关系决定其尺寸与位置的算法:

  • 块布局 - 为了呈现文档而设计出来的布局模式
  • 行内布局 - 为了呈现文本而设计出来的布局模式
  • 表格布局 - 为了用格子呈现 2D 数据而设计出来的布局模式
  • 定位布局 - 为了非常直接地定位元素而设计出来的布局模式,定位元素基本与其他元素毫无关

而flex出现,个人认为全新定义了一种灵活无比的布局方式,灵活到什么地步呢。大致就是,你想怎么样就可以怎么样。

flex

相对于 bfc ifc,flex也会创建一个 伸缩格式化上下文(flex formatting context)。
而这个伸缩容器内部的元素被称为伸缩项目,若伸缩项目内部不包含内容,这个伸缩项目不会被渲染
要搞懂flexbox,必须要有主轴与侧轴的概念!

引用w3官方文档中关于主轴与侧轴的图

主轴与侧轴

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<style type="text/css">
.flexContainer {
display: flex;
flex-flow:row wrap;
flex-direction:row;
}
.flexContainer .child1{
flex:1;
margin: 60px;
background: yellow;
}
.flexContainer .child3{
flex:1;
height: 100px;
margin: 60px;
background: green;
}
</style>
<div class="flexContainer">
<div class="child1">1</div>
<div class="child3">3</div>
</div>

flex_margin.png
看到这里,细心的同学已经发现了,flex布局与block布局很明显的一个区别是,不会存在margin collapse

接下来依次介绍伸缩流布局的一些重要的属性

flex-direction

伸缩流方向

  • row 水平方向排布,按照主轴start -> end的方向
  • row-reverse 按照主轴end -> start 的方向
  • column 垂直方向排布,按照侧轴start -> end方向
  • column-reverse 垂直方向排布,按照侧轴end -> start方向

flex-wrap

伸缩行换行 - 控制容器是否换行,也决定了侧轴方向

  • nowrap 不换行
  • wrap 按照侧轴方向起点到终点
  • wrap-reverse 按照侧轴方向终点到起点

除了nowrap以外的两个属性需要根据伸缩容器的flex-direction属性进行判断
如果flex-direction为row,则伸缩项目的总width超过伸缩容器的width时才会出现是否换行
如果flex-direction为column,则伸缩项目的总height超过伸缩容器的height时才会出现是否换行
伸缩项目没有启用flex属性,并且具有赋值的width,且伸缩项目的总宽大于伸缩容器的宽,才会开启换行模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<style type="text/css">
body{
width: 600px;
}
.flexContainer {
display: flex;
flex-flow: wrap;
flex-direction:row;
}
.flexContainer .child1{
width: 200px;
margin: 20px;
background: yellow;
}
.flexContainer .child3{
width: 200px;
height: 100px;
margin: 20px;
background: green;
}
</style>
</head>
<div class="flexContainer">
<div class="child1">1</div>
<div class="child3">3</div>
<div class="child3">3</div>
<div class="child3">3</div>
</div>

此处采用wrap

还是上面的布局,此处flex-direction采用wrap-reverse

还是上面的布局,此处flex-direction采用nowrap

从上面的例子可以得出 flex-direction 如果为nowrap,则你的布局会表现出伸缩项目宽度与容器宽度成比例的状态

flex-flow

伸缩方向与换行

flex-flow是伸缩方向与换行的一个合写,你可以继续使用之前两个属性也可以用该属性代替

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<style type="text/css">
.container{
display: flex;
flex-flow:row nowrap;
}
.container div{
width: 400px;
height: 200px;
background: yellow;
margin:5px
}
</style>
<div class="container">
<div>
1
</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
</div>

order顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<style type="text/css">
.container{
display: flex;
flex-flow:row nowrap;
}
.container div{
width: 30px;
height: 30px;
background: yellow;
margin:5px
}
</style>
<div class="container">
<div style="order:6">
1
</div>
<div style="order:5">2</div>
<div style="order:4">3</div>
<div style="order:3">4</div>
<div style="order:2">5</div>
<div style="order:1">6</div>
</div>

由这个例子可知
flex提供了一种全新的思路
元素排列的顺序可以完全不依靠文档的上下文,我认为这是flex其中一个很靓的点

圣杯布局

圣杯布局一直是web很流行的一个布局,我们来对比传统方式和flex方式的圣杯布局

flex方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<style type="text/css">
header,footer{
background: gray
}
#main{
display: flex;
flex-direction:row;
}
#main nav,#main aside{
width: 200px;
background: yellow
}
#main article{
flex:1;
height: 200px;
background: green
}
</style>
<header>header</header>
<div id="main">
<nav>nav</nav>
<article>article</article>
<aside>aside</aside>
</div>
<footer>footer</footer>

传统方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style type="text/css">
div:not(#main){
background: gray
}
#main div{
float: left;
width: 33.33%;
height:100px;
background: yellow;
}
</style>
<div>header</div>
<div id="main">
<div>nav</div>
<div>article</div>
<div>aside</div>
</div>
<div>footer</div>

对比两种方式发现

  • 传统方式的盒模型结构在处理百分比宽度与margin,padding的时候会显得比较笨拙
  • 很难处理多列之间固定宽度与百分比宽度的融合

而flex这处理这一问题的时候,以非常灵活的姿态,轻松搞定各种布局难题,我称之为神奇的布局方式

flex:auto

我们在使用flex的wrap进行布局的时候,往往会碰到伸缩项目的总宽度达不到伸缩容器的宽度,而留空
这时候,我们可以使用下flexAuto这个属性,完美解决这个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style type="text/css">
#main{
display: flex;
width: 300px;
flex-flow:row wrap;
border: 1px solid #eee;
}
#main div{
width: 80px;
flex:auto;
background: yellow;
}
</style>
<div id="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>

如上这个例子,我每个盒子本来宽度应该是80,3*80=240,存在空位,如果采用flex:auto后,则会自动平分空位,填满伸缩容器

flex

flex 由[ <’flex-grow’> <’flex-shrink’>? || <’flex-basis’> ]三个值组合
分别代表 扩展比率、收缩比率,以及伸缩基准值

flex-grow

取值:number
初始:0
用来设置伸缩项目扩展比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style type="text/css">
#main {
display: flex;
}
#main div {
flex-grow:1;
margin: 5px;
background: yellow;
}
</style>
<div id="main">
<div>1</div>
<div>2</div>
<div>2</div>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style type="text/css">
#main{
display: flex;
width: 300px;
flex-flow:row wrap;
border: 1px solid #eee;
}
#main div{
width: 80px;
flex:auto;
background: yellow;
}
</style>
<div id="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>

如上这个例子,我每个盒子本来宽度应该是80,3*80=240,存在空位,如果采用flex:auto后,则会自动平分空位,填满伸缩容器

flex

flex 由[ <’flex-grow’> <’flex-shrink’>? || <’flex-basis’> ]三个值组合
分别代表 扩展比率、收缩比率,以及伸缩基准值

flex-grow

取值:number
初始:0
用来设置伸缩项目扩展比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style type="text/css">
#main {
display: flex;
}
#main div {
flex-grow:1;
margin: 5px;
background: yellow;
}
</style>
<div id="main">
<div>1</div>
<div>2</div>
<div>2</div>
</div>

flex-shrink

用来设置收缩比率,指当伸缩项目的总宽或总高超过伸缩容器的高宽的时候,以怎么样的方式进行伸缩

取值
默认 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style>
body{margin: 0}
#container{
width: 100px;
display: flex;
flex-direction:row;
}
#container div {
height: 200px;
width: 60px;
}
#test1 {
background-color: blue;
flex-shrink: 1;
}
#test2 {
background-color: yellow;
flex-shrink: 0.5;
}
</style>
<div id="container">
<div id="test1"></div>
<div id="test2"></div>
</div>

此处 flex-shrink的计算公式:
最后实际的宽度 = 期望的宽度 - 超出的宽度*shrink占总shrink的比例

test1Width = 60 - 20*1/(1+0.5)=47px;
test2Width = 60 - 20*0.5/(1+0.5)=53px;

flex-basis

取值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style>
body{margin: 0}
#container{
width: 100px;
display: flex;
flex-direction:row;
}
#container div {
height: 200px;
width: 60px;
}
#test1 {
background-color: blue;
flex-basis: 100px;
}
#test2 {
background-color: yellow;
flex-basis: 100px;
}
</style>
<div id="container">
<div id="test1"></div>
<div id="test2"></div>
</div>

flex-basis是期望的宽高,最终会按照他的一个比例进行分配实际宽高,在这个例子就是100px/100%=1:1,即每个伸缩项目的宽度占伸缩容器的一半,50px

对齐

flex 中同样也支持margin属性,同时他变得更加强大,如果该值为auto则为反方向置顶

1
2
3
4
5
6
7
8
9
10
11
12
<style type="text/css">
#main{
display: flex;
height: 200px;
}
#main div{
margin-top: auto;
}
</style>
<div id="main">
<div>11</div>
</div>

justify-content

主轴对齐

  • flex-start 从起点开始
  • flex-end 从终点开始
  • center 主轴居中
  • space-between
  • space-around

space-between与space-around之间,我们举个栗子来理清楚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style type="text/css">
#main{
display: flex;
height: 200px;
justify-content:space-between;
}
#main div{
width: 40px;
background: red;
margin: 10px;
}
</style>
<div id="main">
<div>11</div>
<div>11</div>
<div>11</div>
<div>11</div>
</div>

布局不变,我们修改justify-content属性为space-around

口以看明白
between属性将最边上两个伸缩项目的空白区域去除了,然后剩下的项目空白之间等距
around属性是将所有伸缩项目之间空白区域等距

侧轴对齐

侧轴对齐由两个属性组合决定

align-items

* flex-start 侧轴起点
* flex-end 侧轴终点
* center 侧轴中心
* baseline 侧轴起点
* stretch 占满整个伸缩容器

align-self

* auto 使用伸缩容器的align-items
* flex-start 侧轴起点
* flex-end 侧轴终点
* center 侧轴中心
* baseline 
* stretch 占满整个伸缩容器

align-items是用于伸缩容器的,而align-self是用于伸缩项目,如果align-self的值不为auto,则采用align-self的属性,否则使用伸缩容器的align-items属性

这个地方要做一个比较 “baseline”与”flex-start”
首先是”align-items”为”baseline”属性的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style type="text/css">
#main{
display: flex;
height: 200px;
align-items:baseline;
}
#main div{
width: 40px;
line-height: 50px;
background: red;
margin: 0;
}
#main p{
line-height: 40px;
background: yellow;
margin: 0;
}
</style>
<div id="main">
<div>11</div>
<div>11</div>
<div>11</div>
<div>11</div>
<p>11</p>
<div style="line-height:90px;">1111</div>
</div>

“align-items”为”flex-start”属性的

经过对比二者区分应该很明显吧,我就不做过多解释了

flex的baseline

根据上面的栗子,我认为flex的baseline应该是排序后line-height最大值的伸缩项目的baseline

既然flex如此如此好 ,那他有什么缺点吗?
最大的一个问题是兼容!!!
一张引自mozilla官方文档的图片

关于兼容的问题可以学习大漠的文章《使用Flexbox:新旧语法混用实现最佳浏览器兼容》,本文不做展开介绍了。谢谢观看

Contents
  1. 1. flex
    1. 1.1. flex-direction
    2. 1.2. flex-wrap
    3. 1.3. flex-flow
    4. 1.4. order顺序
    5. 1.5. 圣杯布局
      1. 1.5.1. flex方式
      2. 1.5.2. 传统方式
  2. 2. flex:auto
  3. 3. flex
    1. 3.1. flex-grow
  4. 4. flex
    1. 4.1. flex-grow
    2. 4.2. flex-shrink
    3. 4.3. flex-basis
  5. 5. 对齐
    1. 5.1. justify-content
    2. 5.2. 侧轴对齐
      1. 5.2.1. align-items
      2. 5.2.2. align-self
  6. 6. flex的baseline