Flexbox

How flexbox works 

属性#1 display: flex

示例如下

我们有4个不同大小的div包含在一个灰色的div父容器里,每个div都默认设置为:display: block

现在给父容器设置:

1
2
3
#container {
display: flex;
}

实际上我们给这4个div添加了一个 flex context (弹性上下文)
在这个弹性上下文中定位这4个div比传统的CSS要容易得多

属性#2 flex-direction

一个 Flexbox 的父容器有两个轴:主轴和交叉轴。默认情况如下:

默认情况下父容器中的每个元素都会沿着主轴自左向右依次排列。所以父容器设置为 display: flex 后所有的 div 会排列在一行上

但是 flex-direction 属性可以让主轴旋转,如下:

1
2
3
4
#container {
display: flex;
flex-direction: column;
}

注意:flex-direction: column 并不是把 div 从主轴移动到交叉轴上,而是让主轴从水平变为垂直
flex-direction 还有两个值: row-reversecolumn-reverse

属性#3 justify-content

justify-content 用来控制元素在主轴上的对齐方式
先深入理解下主轴和交叉轴的区别。首先设置 flex-direction: row

1
2
3
4
5
#container {
display: flex;
flex-direction: row;
justify-content: flex-start;
}

justify-content 有5个可选值:

  1. flex-start
  2. flex-end
  3. center
  4. space-between
  5. space-around

space-between 会使每个 div 之间产生相同的间隔,但在 div 和父容器之间没有间隔

space-around 会在每个 div 两侧各产生一个相同的间隔,即父容器和最外层的 div 之间的间隔刚好是两个 div 间隔的一半

注意:justify-content 是沿着主轴工作的。 flex-direction 改变的是主轴方向。

属性#4 align-items

如果理解了justify-contentalign-items将会很容易

justify-content 是沿着主轴工作的,而 align-items 则是沿着交叉轴工作的。

首先重置 flex-direction: row 两个轴展示如下:

align-items 有5个可选值:

  1. flex-start
  2. flex-end
  3. center
  4. stretch
  5. baseline

前三个都和justify-content一样,看看后两个:

align-items: stretch: 每个 div 都会充满交叉轴

align-items: baseline: 按照 p 标签的底部对齐

注意:align-items: stretch, 每个 divheight 必须为 auto 否则 height 属性会覆盖 stretch 的效果

对于align-items: baseline,如果 div 内没有 p 标签或者 div 内没有文字或者子标签内没有文字将按照每个 div 的底部对齐。像这样:

为了更好的理解主轴和交叉轴的区别,把 justify-contentalign-items 合在一起,看看在 flex-direction 两种值下的效果

属性#5 align-elf

align-self 允许你手动设置一个元素的对齐方式

这会覆盖掉元素原有的 align-items 属性。因为父容器内元素属性都为 auto, 所以每个 div 都会使用父容器的 align-items 属性值

1
2
3
4
5
6
7
#container {
align-items: flex-start;
}
.square#one {
align-self: center;
}
/* 只有 #one 这个 div 会居中 */

将前两个 div 设置 align-self 属性,剩下的设置 align-items: centerflex-direction: row:


Even more about how flexbox works 

上一节我们已经了解了Flexbox的基本属性:flex-direction, justify-content, align-items, and align-self

属性#1 flex-basis

在上一节,我们主要看了应用在container元素上的属性,这一节,我们专门来看应用在子元素上的属性

在设置其他Flexbox属性之前,flex-basis 控制元素的默认尺寸

下图表示flex-basis可以和 width 属性互换

flex-basiswidth 又有什么区别呢?它与flex axes相对应:

flex-basis 是通过主轴 (main axis) 来影响元素尺寸的

保持 flex-basis 不变,然后切换主轴方向:

注意,我们必须从手动设置高度切换成手动设置宽度。根据flex-direction 的不同,flex-basis 会交替的影响 width height

属性#2 flex-grow

将每个元素的 width 都设置为 120px

flex-grow 的默认值为 0,这意味着子元素不能在父容器内增长 (grow) 他们的宽度
这是什么意思呢?让我们设置每个子元素的 flex-grow: **1**

这些子元素在父容器内均匀的充满了整个空间。flex-grow 的值覆盖了 width的值

flex-grow: 1 到底意味着什么呢,如果我们改为 flex-grow: 999

结果完全一样。这是因为 flex-grow 不是个绝对值——而是一个相对值。

如果我们设置每个子元素的 flex-grow: 1,然后再调整第3个子元素的 flex-grow值,看看有什么变化:

用一点简单的数学知识就可以理解:
每个子元素的 flex-grow 的初始值为1,加起来总数为6。父容器因此划分为6个单独的区域,每个子元素都占据了1/6父容器的空间

同理,设置第3个子元素的 flex-grow值为2,这时总的flex-grow值为:1+1+2+1+1+1,父容器划分为7个单独的区域,第3个子元素占据了2/7父容器的空间,剩下的每个子元素都占据了1/7父容器的空间

当设置第3个子元素的 flex-grow值为3的时候,总的flex-grow值为:1+1+3+1+1+1,父容器划分为8个单独的区域,第3个子元素占据了3/8父容器的空间,剩下的每个子元素都占据了1/8父容器的空间

实际上 flex-grow 就是一个比例关系,设置每个子元素 flex-grow: 4, 第三个子元素 flex-grow: 12, 其实和 1:3的情况是一样的

真正重要的是每个子元素的 flex-grow 和其它子元素的 flex-grow 比例关系

最后要注意的是,和 flex-basis 属性一样,flex-grow 属性也是沿着主轴工作的,子元素只改变其宽度,除非设置 flex-direction: column

属性#3 flex-shrink

flex-shrink 的作用和 flex-grow 恰恰相反,来确定一个元素的缩小比例

flex-shrink 的主要用途是指定哪些子元素要缩小,哪些子元素不缩小。flex-shrink 的默认值为1——意味着子元素会随着父容器缩小而相应缩小

现在设置第三个元素的 flex-shrink 的值为0,禁止随父容器缩小而相应缩小,因此它不会收缩到自己的宽度以下(这里它的宽度为120px),但可以增长宽度以适应父容器的宽度。

同样的,flex-shrink 也是比例关系

If one box has flex-shrink of 6, and the rest have flex-shrink of 2, the one box will shrink 3x as fast as the rest, as space compresses.
Note the wording there: the square with a 3x flex-shrink will shrink 3x as fast. This does not mean it will shrink 1/3 of the width.

属性#4 flex

flex 属性是把 flex-grow flex-shrink flex-basis 综合到了一起
默认值为 0 (flex-grow) 1 (flex-shrink) auto (flex-basis)

最后一个例子,我们简化成只有两个元素:

1
2
3
4
5
6
.square#one {
flex: 2 1 300px;
}
.square#two {
flex: 1 2 300px;
}

它们有相同的 flex-basis ,这意味着如果有足够的空间容纳它们(父容器的宽度为600px,还有margin和padding),它们都会是300px宽

元素1将会以2x的速度增长宽度,元素2将会以2x的速度缩小宽度

How Things Shrink And Grow

当元素1 (.square#one) 增长时它不会增长到元素2 (.square#two) 的两倍;同样元素2 (.square#two) 也不会缩小为元素1 (.square#one) 的一半
这是因为不是它们的大小比例为2:1或1:2,而是它们的收缩和增长速度

一点数学计算

父容器的初始宽度为640px,除去两边各 20px 的 padding 后,两个子元素的 flex-basis 为 300px
当设置父容器的宽度为 430px 时,减少了 210px 的空间, 元素1 flex-shrink: 1 减少了 70px ; 元素2 flex-shrink: 2少了 140px

当设置父容器的宽度为 340px 时,减少了 300px 的空间, 元素1 减少了 100px; 元素2 少了 200px
减少的比例正好也是 2:1

flex-grow 也是同样道理。设置父容器的宽度为 940px 时,增加了了300px的空间, 元素1增加了额外的 200 px,元素2增加了额外的 100px

Conclusion

As a final recap: flex-basis controls how large an element will be along the main-axis before any growing or shrinking occurs. Flex-grow determines how much it will grow in proportion to sibling elements, and flex-shrink determines how much it will shrink.


第一节翻译自How flexbox works — explained with big, colorful, animated gifs
第二节翻译自Even more about how flexbox works — explained in big, colorful, animated gifs