长久以来,唯一可用的且有稳定的跨浏览器兼容性的能用来构建 CSS 布局的工具只有 floats 和 positioning。它们是既可行,表现也不错的布局方案,但是在某些布局方面它们就有限制,并且难以实现。弹性盒子使得很多布局任务变得更加容易。
首先,我们需要选择将哪些元素将设置为柔性的盒子。我们需要给这些 flexible 元素的父元素 display 设置一个特定值。
section {
display: flex;
}
就这样一个简单的声明就给了我们所需要的一切。 我们的多列布局具有大小相等的列,并且列的高度都是一样。 这是因为这样的 flex 项(flex容器的子项)的默认值是可以解决这些的常见问题的。
假如你想设置行内元素为 flexible box,也可以置 display 属性的值为 inline-flex。
flex模型说明
- 主轴(main axis)是沿着 flex 元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为 main start 和 main end。
- 交叉轴(cross axis)是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 cross start 和 cross end。
- 设置了
display: flex
的父元素(在本例中是<section>
)被称之为 flex 容器(flex container)。 - 在 flex 容器中表现为柔性的盒子的元素被称之为 flex 项(flex item)(本例中是
<article>
元素。
列与行排列
弹性盒子提供了 flex-direction 这样一个属性,它可以指定主轴的方向(弹性盒子子类放置的地方)— 它默认值是 row,这使得它们在按你浏览器的默认语言方向排成一排
按列排列:
flex-direction: column
你还可以使用flex-direction的 row-reverse 和 column-reverse 值反向排列 flex 项目。
换行问题
当你在布局中使用定宽或者定高的时候,可能会有一个问题出来即处于容器中的 弹性盒子子元素会溢出,破坏了布局。
解决此问题的一种方法是将以下声明添加到 section css 规则中:
flex-wrap: wrap
flex-flow缩写
存在着 flex-direction 和 flex-wrap — 的缩写 flex-flow。比如,你可以将
flex-direction: row;
flex-wrap: wrap;
替换为:
flex-flow: row wrap;
flex项的动态尺寸
控制 flex 项占用空间的比例:
article {
flex: 1;
}
这是一个无单位的比例值,表示每个 flex 项沿主轴的可用空间大小。我们设置 <article> 元素的 flex 值为 1,这表示每个元素占用空间都是相等的,占用的空间是在设置 padding 和 margin 之后剩余的空间。因为它是一个比例,这意味着将每个 flex 项的设置为 400000 的效果和 1 的时候是完全一样的。
在上一个规则下添加:
article:nth-of-type(3) {
flex: 2;
}
现在当你刷新,你会看到第三个 <article> 元素占用了两倍的可用宽度和剩下的一样 — 现在总共有四个比例单位可用。 前两个 flex 项各有一个,因此它们占用每个可用空间的1/4。 第三个有两个单位,所以它占用2/4或这说是1/2的可用空间。
还可以指定 flex 的最小值:
article {
flex: 1 200px;
}
article:nth-of-type(3) {
flex: 2 200px;
}
这表示“每个flex 项将首先给出200px的可用空间,然后,剩余的可用空间将根据分配的比例共享“。
flex的缩写与全写
flex
是一个可以指定最多三个不同值的缩写属性:
- 第一个就是上面所讨论过的无单位比例。可以单独指定全写
flex-grow
属性的值。 - 第二个无单位比例 —
flex-shrink
— 一般用于溢出容器的 flex 项。这指定了从每个 flex 项中取出多少溢出量,以阻止它们溢出它们的容器。 这是一个相当高级的弹性盒子功能,我们不会在本文中进一步说明。 - 第三个是上面讨论的最小值。可以单独指定全写
flex-basis
属性的值。
我们建议不要使用全写属性,除非你真的需要(比如要去覆盖之前写的)。
水平和垂直对齐
div {
display: flex;
align-items: center;
justify-content: space-around;
}
align-items
控制 flex 项在交叉轴上的位置。
- 默认的值是
stretch
,其会使所有 flex 项沿着交叉轴的方向拉伸以填充父容器。如果父容器在交叉轴方向上没有固定宽度(即高度),则所有 flex 项将变得与最长的 flex 项一样长(即高度保持一致)。我们的第一个例子在默认情况下得到相等的高度的列的原因。 - 在上面规则中我们使用的
center
值会使这些项保持其原有的高度,但是会在交叉轴居中。这就是那些按钮垂直居中的原因。 - 你也可以设置诸如
flex-start
或flex-end
这样使 flex 项在交叉轴的开始或结束处对齐所有的值。查看align-items
了解更多。
可以用 align-self
属性覆盖 align-items
的行为。比如,你可以这样:
button:first-child {
align-self: flex-end;
}
justify-content
控制 flex 项在主轴上的位置。
- 默认值是
flex-start
,这会使所有 flex 项都位于主轴的开始处。 - 你也可以用
flex-end
来让 flex 项到结尾处。 center
在justify-content
里也是可用的,可以让 flex 项在主轴居中。- 而我们上面用到的值
space-around
是很有用的——它会使所有 flex 项沿着主轴均匀地分布,在任意一端都会留有一点空间。 - 还有一个值是
space-between
,它和space-around
非常相似,只是它不会在两端留下任何空间。
flex项排序
弹性盒子也有可以改变 flex 项的布局位置的功能,而不会影响到源顺序(即 dom 树里元素的顺序)。
button:first-child {
order: 1;
}
- 所有 flex 项默认的
order
值是 0。 - order 值大的 flex 项比 order 值小的在显示顺序中更靠后。
- 相同 order 值的 flex 项按源顺序显示。所以假如你有四个元素,其 order 值分别是2,1,1和0,那么它们的显示顺序就分别是第四,第二,第三,和第一。
- 第三个元素显示在第二个后面是因为它们的 order 值一样,且第三个元素在源顺序中排在第二个后面。
排在主轴的最前面:
button:last-child {
order: -1;
}
flex嵌套
弹性盒子也能创建一些颇为复杂的布局。设置 flex 项为 flex 容器也是没有什么问题的,它的孩子也就表现为 flexible box 了。
这个例子的 HTML 是相当简单的。我们用用一个 <section>
元素包含了三个 <article>
。第三个 <article>
元素包含了三个 <div>
:
section - article
article
article - div - button
div button
div button
button
button
首先,我们设置 <section>
的子代布局为 flexible box。
section {
display: flex;
}
下面我们给 <article>
元素设置一些 flex 值。特别注意这里的第二条规则—我们设置第三个 <article>
元素里的子元素同样表现为 flex 项,但是这次我们使它们放置为列。
article {
flex: 1 200px;
}
article:nth-of-type(3) {
flex: 3 200px;
display: flex;
flex-flow: column;
}
接下来,我们选择了第一个 <div>
。首先使用 flex: 1 100px;
简单的给它一个最小的高度 100px,然后设置它的子代(<button>
元素)为 flex 项。在这里我们将它们放在一个包装行中,使它们居中对齐,就像我们在前面看到的单个按钮示例中所做的那样。
article:nth-of-type(3) div:first-child {
flex: 1 100px;
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: space-around;
}
最后,我们给按钮设置大小,有意思的是我们给它一个值为1的 flex 属性。如果你调整浏览器窗口宽度,你会看到这是一个非常有趣的效果。按钮将占用尽可能多的空间,尽可能多的坐在同一条线上,但是当它们不再适合在同一条线上,他们会到下一行去。
button {
flex: 1;
margin: 5px;
font-size: 18px;
line-height: 1.5;
}