Flex 布局
概念
Flex 布局是在水平与垂直两个 有向轴 上描述子元素的布局行为。它主要描述的是子元素在单列(或单行)上的单维布局,更复杂的两维度网格布局使用 Grid 布局会更好描述一点。
它描述了子元素布局的种类主要有如下几种:
- 在轴上的 位置。是在轴的起始、中间、末尾位置。
- 剩余轴空间的分配。是分配剩余空间,还是按某个比例撑满剩余空间?
- 元素在整个 Flex 容器顺序。
- 元素在 “Line Box” 里的排列方式。是相对 “Line Box” 交叉方向的起始、中间、末尾对齐,还是撑满。
有向轴的方向与 Flex 容器的文本书写方向有关,这个其实比较复杂。大部分情况下,我们都是字之间从左往右排列,行之间自上而下排列的书写方向,所以一般以这个为默认场景来说明 Flex 轴的方向。
- 当轴是水平轴时,其默认方向是从左往右的;
- 当轴是垂直轴时,其默认方向是从上往下的;
举几个例子展开说明一下。
flex-direction
这个属性定义的是主轴的方向。它的默认值是 row
,也就是说默认主轴是水平方向的轴,那么其方向就是从左往右(因为默认文本方向是从左往右,后续不再解释)。因为主轴是水平轴,所以副轴就是垂直轴,那么其方向就是从上往下(同样是因为默认文本行是自上而下怕列,后续不再解释)。
Flex 只提供了修改主轴方向的属性。当 flex-direction
的值为 row-reverse
时,其含义就是主轴的方向与文本水平排列方向相反。那么在默认场景下,它的方向就变成从右往左。而副轴依然是垂直轴,其方向依然只能是从上往下。
当主轴变为垂直轴时,如 flex-direction: column
,那么其方向就是从上往下,而副轴则是水平轴,其方向就是从左往右。当 flex-direction: column-reverse
时,主轴的方向就是从下往上,副轴方向不变。
align-content与align-items
我们日常用得最多的,其实是 align-items
。在我第一次接触 Flex 布局的时候,我就经常在想:“为什么控制元素在主轴行为的属性叫 justify-content,而控制元素在副轴行为的属性却叫 align-items
而不是 align-content
呢?
实际上,控制元素在副轴行为的属性就是 align-content
。
而 align-items
控制的是在一个 “Line Box”(姑且这么叫吧,想象 flex-wrap: wrap
的场景下,换成多行,每一行就是一个 “Line Box”)内,元素在这个 “Line Box” 内副轴方向上的排列属性。
那么 align-content
控制的就是这些 “Line Box” 在副轴方向上的排列属性。
我们通过构建一个例子来说明一下:
<!-- pg-title: align-items 与 align-content -->
<div class="container">
<!-- 第1个 “Line Box” -->
<div class="normal">Normal</div>
<div class="tall">Tall</div>
<div class="low">Low</div>
<!-- 第2个 “Line Box”,特意用 align-self 修改了几个元素 -->
<div class="normal" style="align-self: center;">Normal</div>
<div class="tall">Tall</div>
<div class="low" style="align-self: flex-start;">Low</div>
<!-- 第3个 “Line Box” -->
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<!-- 第4个 “Line Box” -->
<div class="normal">Normal</div>
<div class="normal">Normal</div>
</div>
.container {
box-sizing: border;
margin: 20px;
border: 1px solid black;
width: 399px;
height: 400px;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-content: flex-start;
align-items: flex-end;
}
.container > div {
width: 100px;
border: 1px solid blue;
}
.tall {
height: 100px;
}
.low {
height: 20px;
}
上面的例子,刻意制造了一个宽度 399px 的 Flex 容器,每个子元素固定宽度为 100px,这样每排最多只能容纳 3 个元素,从而制造出了 4 个 “Line Box”,这些 “Line Box“ 都是我虚构出来的,在 HTML 里加了备注。
试着调整下 align-content
与 align-items
的属性。你就会理解,align-content
控制的对象是 “Line Box” 而不是直接控制子元素。
不过实际情况很少用得这么复杂。实际上,有这种需求的时候转而用 Grid 布局或许更好一些。