/ CSS

Flexbox 完全指南

背景

CSS Flexbox Layout(Flexible Box)模块(目前为 W3C 最终草案2016.03.01 更新为 CR —— 候选推荐规范)致力于提供一种更高效的布局方式,即便子项尺寸未知(或动态)的情况下,对齐、分布容器子项之间的空间,因此谓之「flex」。

弹性布局背后的主要思想是让容器能够改变子项的宽、高以及顺序,以最合适的方式填充可用空间(以适应各种显示设备和屏幕尺寸)。弹性容器扩展子项以填充可用空间,或者收缩子项防止溢出。

与常规布局方式相反,Flexbox 布局是方向无关的(块级元素基于垂直方向,行内元素基于水平方向)。虽然常规布局方式在网页上使用还行,但对于支持大型、复杂的应用缺乏灵活性(特别是方向改变、调整大小、拉伸、收缩等场景)。

注:Flexbox 布局非常适合组织应用组件和小型布局,而 Grid 布局则为大型应用布局设计。

基础知识和术语

Flexbox 是一个完整的 CSS 模块,而不是一个单一属性。Flexbox 包含了一系列属性,一部分用于 flex 容器,另一部分用于子元素(flex 子项)。

常规布局基于块级和行内流动方向,Flexbox 基于「弹性流动方向(flex-flow directions)」。搂一眼这张来自规范的图,其阐释了弹性布局背后的主要思想。

基本上,子项将沿着主轴(main axis,从 main-startmain-end)或者交叉轴(cross axis,从 cross-startcross-end)二者之一排列。

  • main axis - 弹性容器的主轴是子项布局的主坐标轴。注意,主轴不一定是水平方向的,取决于 flex-direction 属性的设置。
  • main-start | main-end - 弹性子项从 main-startmain-end 被放置到容器中。
  • main size - 主要尺寸是弹性项目主坐标轴的尺寸(宽度或者高度之一,由主轴的方向决定)。
  • cross axis - 垂直于主轴的坐标轴称为交叉轴(cross axis),其方向依赖于主轴的方向。
  • cross-start | cross-end - 子项将从 cross-startcross-end 填满容器。
  • cross size

Flexbox 属性

应用于弹性容器的属性

display

定义一个弹性容器,为直接子元素启用弹性环境。

.container {
  display: flex; /* or inline-flex */
}

注意:弹性容器上的 CSS columns 将不起作用。

flex-direction

建立主轴,定义子项在容器中的排列方向。

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
  • row(默认):ltr 模式中从左到右,rtl 模式中从右到左
  • row-reverseltr 模式中从右到左,rtl 模式中从左到右
  • column:和 row 一样,不过是从上到下
  • column-reverse:和 row-reverse 一样,不过是从下到上

flex-wrap

默认地,弹性项将尝试在一行内伸缩适应。通过 flex-wrap 属性可以设置是否换行以及换行后排列的起点。

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap(默认):单行,ltr 模式中从左到右,rtl 模式中从右到左
  • wrap:多行,ltr 模式中从左到右,rtl 模式中从右到左
  • wrap-reverse: 多行,排列方向与 wrap 相反

flex-flow

flex-directionflex-wrap 属性的简写,默认为 row nowrap

flex-flow: <'flex-direction'> || <'flex-wrap'>

justify-content

定义在主轴方向上的对齐方式。

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}
  • flex-start(默认):向开始线对齐
  • flex-end:向结束线对齐
  • center:居中对齐
  • space-between:沿着主轴分布,第一项对齐到开始线,最后一项对齐到结束线
  • space-around:沿着主轴等边距分布

align-items

定义交叉轴上的对齐方式。

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}
  • flex-start:对齐到 cross-start 线
  • flex-end:对齐到 cross-end 线
  • center:沿交叉轴中居中对齐
  • baseline:对齐到基准线
  • stretch(默认):延展填满容器(如果设置了 min-width/max-width 则使用设置的值)

align-content

定义容器内各行沿交叉轴的排列方式(只有一行的时候无效)。

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
  • flex-start
  • flex-end
  • center
  • space-between
  • space-around
  • stretch(默认)

应用于弹性子项的属性

order

order 属性可以调整子项在容器中的排列顺序,值越大越靠后。

.item {
  order: <integer>;
}

flex-grow

定义弹性项的沿主轴的伸张比例,值为非负数

.item {
  flex-grow: <number>; /* default 0 */
}

flex-shrink

定义弹性项收缩方式,值为非负数,默认为 1

.item {
  flex-shrink: <number>; /* default 1 */
}

即剩余空间不够(为负值)时,子项根据定义的值收缩,以适应容器空间。属性值越大,收缩的比例越大;为 0 时不收缩。

This component sets flex-shrink longhand and specifies the flex shrink factor, which determines how much the flex item will shrink relative to the rest of the flex items in the flex container when negative free space is distributed.

flex-basis

定义剩余空间分配前元素的默认大小,默认为 auto。更多细节查看此图

This component sets the flex-basis longhand and specifies the flex basis: the initial main size of the flex item, before free space is distributed according to the flex factors.

.item {
  flex-basis: <length> | auto; /* default auto */
}

flex

flex-grow flex-shrink flex-basis 三个属性合并简写,第二、三个值可选,默认为 0 1 auto建议使用简写方式。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

举例说明(查看):

<div class="container">
  <div class="c1">Child One</div>
  <div class="c2">Child Two</div>
</div>
div {
  outline: 1px solid red;
}

.container {
  display: flex;
}

.c1 {
  flex: 1 1 100px;
  color: green;
}

.c2 {
  flex: 2 2 100px;
  color: purple;
}

这个例子中,两个子项预期的理想宽度(flex-basis)为 50px

  • 如果容器宽度大于 200px,则根据 flex-grow 值,剩余空间的 1/3 分给 .c1,2/3 分给 .c2演示);
  • 如果容器宽度小于 200px,假设是 170px,则根据 flex-shrink 比例,.c1 收缩 10px,.c2 收缩 20px(演示)。

align-self

定义弹性项的对齐方式,值含义同 align-items

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

例子

兼容性问题

浏览器支持

  • 兼容性列表:参见 Can I use
  • Flexbugs - Flexbox 常见 bug 收集
  • 建议按照标准属性编写,然后使用 Autoprefixer 自动添加浏览器前缀

注意事项

由于 2009 版规范 没有 flex-wrapflex-shrinkflex-basis 相对应的属性,使用时如果需要支持按照旧版规范实现的 flexbox 的浏览器,则应该注意避免使用以上三个属性(参考)。

2016.06.22 Update:

针对只支持 09 版规范的用户代理回退处理方案:

  • flex-wrap:通过特定 hook 在子项上应用 display: inline-block;
  • flex-basis:设置元素的 width
  • flex-shrink无解,好在使用的场景并不多。

另外,以 Android 上以 UC 浏览器为代表用户代理,flex 子项一定要是 block 元素,否则不能正确应用 flexbox 相关样式。

Chrome 不收缩图片问题

2016.04.19 补充

Chrome 从某个版本开始,处理弹性上下文中的图片时,会保持图片的实际尺寸,不作收缩处理(在 Chrome 49 上验证了这个问题,演示)。

解决方式是不要把图片直接作为弹性子项,给图片加一个容器,并设置图片的宽度为 100%演示)。

参考链接

2016.05.10 Update:

via A Complete Guide to Flexbox