背景
Flexbox 布局 (FLexible Box)模块(现在处于W3C的最终征求意见稿(Last Call Working Draft)阶段)意在提供一个更为有效的方式来进行布局、对齐和分配一个容器内元素之间的空间,即使他们的大小是未知的或者动态的(这也是flex(弹性的)这个单词的由来)。
flex布局的主要思想是,让容器能够改变它的子元素的宽度/高度(甚至顺序),从而更好地填充可用的空间(主要是为了适应所有种类的设备和屏幕大小)。一个 flex 容器可以扩展它的子元素从而填充可用的空间,或者使他们收缩从而避免溢出。
最重要的,flexbox 布局是可以改变方向的。与之相对的是传统布局(block是垂直方向的从上到下,inline是水平方向的从左到右)。虽然他们在页面上表现良好,但是他们缺乏弹性(字面意义上的缺乏弹性)来适应大型的或者复杂的应用(尤其是遇到方向的改变、调整大小、伸展、收缩等等这些情况时)。
注意:Flexbox 布局最适合应用的组件、小规模的布局,而 Grid 布局更适于大规模布局。
基本术语
因为 flexbox 是一整个模块而不是单一的属性,所以他涉及很多东西,包括一组属性。他们中一些要设置在容器上(父容器,被称作 flex容器),还有一些要设置在子元素上(被称作 flex子元素)。
如果说传统的布局是基于块级或行级文档流方向的,那么flex布局是基于 “flex流方向(flex-flow directions)”的。请看下面来自标准的图片,它解释了关于flex布局的主要思想。
基本上,子元素要么根据主轴(main axis,从主轴开始到主轴结束 )排列或者交叉轴(从交叉轴开始到交叉轴结束)排列。
- 主轴 - flex容器的主轴是flex子元素的首要排列方向。要注意的时,主轴并不一定是水平的;实际方向要根据
flex-direction
属性确定(后面详细说明)。 - 主轴起点|主轴终点 - flex子元素在flex容器内从 主轴起点 到 主轴终点 排列。
- 主轴尺寸 - 一个元素的主要尺寸要么是它的宽度(width)要么是它的高度(height)。这要取决于哪一个属性对着主轴方向。
- 交叉轴 - 垂直于主轴方向的轴称之为交叉轴。它的方向取决于主轴方向。
- 交叉轴起点|交叉轴终点 - Flex行被flex子元素填充,从交叉轴起点到交叉轴终点。
- 交叉轴尺寸 - 一个元素的交叉轴尺寸要么是它的宽度(width)要么是它的高度(height)。这要取决于哪一个属性对着交叉轴方向。
译者注:交叉轴(cross-axis)也被翻译做侧轴、旁轴。
flex容器的属性(flex container)
译者注:不同于常规布局,flex布局依赖于flex容器和flex子元素共同配合完成。所以要在flex容器上设定一些属性。
display
这个属性定义了一个flex容器;可以设定为 inline(内联) 元素 或者 block(块级)元素。它给它的所有直接子元素提供了一个 flex 上下文(环境)。
//CSS
.container{
display:flex; /* 或者 inline-flex */
}
- 注意 CSS 列(columns)在 flex容器 上不起作用。
- float、clear和vertical-align在伸缩项目上没有效果。
flex-direction
这个确立了主轴,也就是定义了flex子元素在flex容器中排列的方向。Flexbox(不考虑换行)是一个单方向的布局概念。可以认为flex子元素要么在水平行上要么在垂直列上进行排列。
//CSS
.container{
flex-direction:row | row-reverse | column | column-reverse;
}
- row (默认):在ltr排版方式下从左到右;在rtl排版方式下从右到左
- row-reverse :在ltr排版方式下从右到左;在ltr排版方式下从左到右
- column:和 row 类似,但是从上到下排列
- column-reverse:和 row-reverse 一样但是从下到上排列
flex-wrap
默认情况下,flex子元素会尝试填充一行。你可以通过设置这一属性允许元素换行来改变这一点。在这里方向属性(flex-direction
)同样发挥作用,它可以改变新的行堆积的方向。
//CSS
.container{
flex-wrap: nowrap | wrap | wrap-reverse;
}
- nowrap(默认值):单行(不换行)。ltr下从左到右排列,rtl下从右到左排列。
- wrap:多行(换行)。ltr下从左到右排列排列;rtl下从右到左排列。
- wrap-reverse:多行(换行)。ltr下从右到左排列;rtl下从左到右排列。
flex-flow
这是对于 flex-direction
和 flex-wrap
属性的简洁表示(就像font之于 font-size、font-family、font-weight
一样),同时定义了 flex容器 的主轴和交叉轴。 默认值是 row nowrap
。
//CSS
flex-flow:<'flex-direction'> || <'flex-wrap'>
justify-content
这个属性定义了沿着主轴方向元素的对齐方式。
它会帮助分配容器内多余的空间,无论flex子元素是非弹性的,还是弹性的但是达到了最大尺寸。对于溢出一行的元素它同样会发挥作用。
//CSS
.container{
justify-content:flex-start | flex-end | center | space-between | space-around;
}
- flex-start (default):子元素向一行的起始处堆积。(想象text-align:left)
- flex-end:子元素向一行结尾处堆积。
- center:子元素在一行的中间排列。(想象text-align:center)
- space-between:子元素平均分布在一行中;第一个子元素紧贴行首,最后一个元素紧贴行末。
- space-around:子元素平均分布在一行中,周围有着相同的空间。注意视觉上这些空间并不是相等的,因为所有的元素在两侧都有相等的空间。第一个元素与容器边缘中间仅有以单位的空间,而它和下一个元素之间会有两个单位的空间,因为下一个元素本身周围有着自己的空间。
aligh-items
这个属性定义 flex子元素 在当前行沿着交叉轴如何排布。可以认为它是 justify-content
的交叉轴版本。
//CSS
.container{
align-items:flex-start | flex-end | center | baseline | stretch ;
}
-
flex-start
:元素在交叉轴开始处的margin边缘将紧贴交叉轴的开始处。 -
flex-end
:元素在交叉轴结束处的margin边缘将紧贴交叉轴的结束处。 -
center
:元素在交叉轴上居中。 -
baseline
:元素根据他们的baseline对齐。 -
stretch
(默认值):伸展子元素以填充容器(max-width/min-width仍会起作用)。
align-content
在容器的交叉轴方向上有多余空间时,这个属性会对齐容器的行,类似于 justify-content
在主轴上对齐单独的子元素。
注意:当flex容器内部仅有一行 flex子元素 的时候,这个属性不起作用。
//CSS
.container{
align-content:flex-start | flex-end | center | space-between | space-around | stretch;
}
-
flex-start
:所有行朝着容器的开始处堆积。 -
flex-end
:所有行朝着容器的结束处堆积。 -
center
:所有行在容器中间分布。 -
space-between
:所有行平均分布。第一行在容器的起始处,最后一行在元素的结束处。 -
space-around
:所有行平均分布,周围有着相等的空间。 -
stretch
(默认值):所有行伸展以填充剩余的空间。
flex子元素的属性(flex items)
order
默认情况下,flex子元素以源代码中的顺序分布。但是, order
属性可以控制他们他们在 flex容器 中的表现。
//CSS
.item{
order:<integer>; //默认是0;
}
flex-grow
这个属性定义了元素可以根据需要扩展(grow)的能力。它接受一个无单位的值用以作为比例。它表明了一个子元素在 flex容器中 应该占有多大比例的空间。
如果所有的子元素都设置 flex-grow
值为1,那么所有的子元素都会获得相等的空间。如果给其中一个子元素的值为2,那么它将占用其他元素两倍的空间。
//CSS
.item {
flex-grow: <number>; /* 默认0 */
}
负值无效。
flex-shrink
这个属性给了元素在需要的情况下收缩的能力。
//CSS
.item {
flex-shrink: <number>; /*默认值 1*/
}
负值无效。
flex-basis
这个属性定义了在多余的空间被分配之前,一个元素的默认大小。根据 flex-direction
定义的不同,main-size
的值会对应 height
或者 width
。
//CSS
.item {
flex-basis: <length> | auto; /* 默认值 auto */
}
如果设置为0,那么内容周围的空间将不被考虑。如果设置为 auto
,那么多雨的空间会根据它的 flex-grow
属性值来分配。
flex
该值是 flex-grow
, flex-shrink
, flex-basis
的缩写。第二个和第三个参数(flex-shrink
和flex-basis
)是可选的。默认值是 0 1 auto
。
//CSS
.item {
flex:none | [<'flex-grow'> <'flex-shrink'> || <'flex-basis'> ];
}
建议用属性缩写代替单独的属性。这个缩写会聪明地设置其他值。
align-self
该属性允许元素覆盖默认的对齐方式(或者 align-items
定义的对齐方式)。
参见 align-items
的解释来理解本属性可选的值。
//CSS
.item {
align-self:auto | flex-start |flex-end | center | baseline | stretch;
}
注意 float
、 clear
和 vertical-align
对于 flex子元素 没有效果。
样例
我们先看一个简单的例子,它解决了一个几乎每天都要遇到的问题:完美的居中。没有比用 flexbox 更简单的方法了。
//CSS
.parent {
display:flex;
height:300px; /* 或者其他的值 */
}
.child {
width: 100px; /* 任意值 */
height: 100px; /* 任意值 */
margin: auto; /* 神奇所在! */
}
这个方法基于一个很简单的事实:margin
属性 设置为 ’auto‘
的 flex子元素 会占用多余的空间。 所以设置垂直方向上的 margin 为 auto
会使得元素在两个坐标轴上完美地居中。
现在让我们用一些其他的属性。
考虑一个有6个元素的列表,所有元素都有一个很漂亮的尺寸,但是可以自动调整大小。我们想要他们优雅地平均分布在主轴上,这样当我们缩放浏览器的时候,一切依然显示很完美。 (不用媒体查询 media query).
//CSS
.flex-container{
/* 我们先创建一个 flex布局 上下文 */
display:flex;
/* 之后我们定义主轴方向和是否允许自动换行 */
//等同于
// flex-direction:row;
// flex-warp:wrap;
flex-flow: row wrap;
/* 最后我们定义如何分配剩余的空间 */
justify-content:space-around;
}
完成。其他的一切都是其他样式定义要考虑的。下面是在codepen上展示的一个例子。到codepen上查看,并试着调整你浏览器窗口去看发生什么事?
See the Pen Demo Flexbox 3 by Hugo Giraudel (@HugoGiraudel) on CodePen.
让我们试一下其他的一些东西。想象一下我们在页面顶部有一个右对齐的导航栏,但是我们想要它在中等大小的屏幕上居中,在小屏幕上单行显示。很简单。
//CSS
/* 大屏幕 */
.navigation {
display:flex;
flex-flow:row wrap;
/* 子元素右对齐 */
justify-content:flex-end;
}
/* 中型屏幕 */
@media all and (max-width:800px) {
/* 中型屏幕上,平均分布空白空间用以居中 */
justify-content:space-around;
}
/* 小型屏幕 */
@media all and (max-width:500px) {
.navigation {
/* 在小型屏幕上,用列方向而不是行方向 */
flex-direction: column;
}
}
See the Pen Demo Flexbox 2 by Hugo Giraudel (@HugoGiraudel) on CodePen.
让我们感受一下 flex子元素 的弹性,尝试一些更好的东西。比如移动优先的3栏布局,header和footer都占用全部宽度,并且实际顺序与源代码顺序相独立。
//CSS
.wrapper {
display: flex;
flex-flow:row wrap;
}
/* 设置所有的子元素100%宽度 */
.header, .main, .nav, .aside, .footer {
flex:1 100%;
}
/* 源代码中顺序如下:
* 1. header
* 2. nav
* 3. main
* 4. aside
* 5. footer
*/
/* 中等屏幕 */
@media all and (min-width: 600px) {
/* 设定两个侧边栏共用一行 */
.aside { flex: 1 auto;}
}
@media all and (min-width:800px) {
.main {flex: 2 0;}
.aside-1{ order:1; }
.main { order:2; }
.aside-2{ order:3; }
.footer { order:4; }
}
See the Pen Demo Flexbox 3 by Hugo Giraudel (@HugoGiraudel) on CodePen.
Flexbox 前缀(prefix)
Flexbox需要添加一些前缀用以尽可能支持多的浏览器。但是它不是简单地添加前缀就好(类似于-webkit-、-moz-、-ms-
),它有着完全不同的属性和值。因为Flexbox的标准经过了很多次修改。造成了 "old"、“tweener”、“new”三个版本。
解决这个问题最好的办法可能是写的时候用最新的语法来写,并且用 Autoprefixer 这个工具来处理降级。
当然,可以用 Sass的@mixin 方法来帮助解决这个问题,下面有一个例子展示了应该做哪些处理。
@mixin flexbox() {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
@mixin flex($values) {
-webkit-box-flex: $values;
-moz-box-flex: $values;
-webkit-flex: $values;
-ms-flex: $values;
flex: $values;
}
@mixin order($val) {
-webkit-box-ordinal-group: $val;
-moz-box-ordinal-group: $val;
-ms-flex-order: $val;
-webkit-order: $val;
order: $val;
}
.wrapper {
@include flexbox();
}
.item {
@include flex(1 200px);
@include order(2);
}
相关属性
其他资源
Flexbox in the CSS specifications
Mixing syntaxes for best browser support on CSS-Tricks
Flexbox by Raphael Goetter (FR)
Bugs
Flexbox当然存在bug。我见过的关于这些bug的最好的集合是 Philip Walton 和 Greg Whitworth 的Flexbugs。这是一个开源的地方来对这些进行记录,我给出这个链接就好。
浏览器支持
flex的版本划分如下:
- (new)表示最近的标准的语法(例如:
display:flex;
) - (tweener)表示2011年版本的语法(例如:
display:flexbox;
) - (old)表示最早的2009年的语法(例如:
display:box;
)
|chrome |Safari |Firefox |Opera |IE |Android |iOS |
|---|
|21+(new) |3.1+(old) |2-21(old) |12.1+(new) |10(tweener)|2.1+(old)|3.2+(old)|
|20-(old) |6.1+(new) |22+(new) | |11+(new) |4.4+(new)|7.1+(new)|
有关如何混合多种语法达到最好的浏览器兼容效果,请参阅这两篇文章 CSS-tricks 和 this article (DevOpera)。
翻译完成之后才发现网上已经有了翻译了。 W3plus-一个完整的Flexbox指南
英文原文:http://css-tricks.com/snippets/css/a-guide-to-flexbox
中文译文:http://www.w3cplus.com/css3/a-guide-to-flexbox.html
其他翻译:http://www.w3cplus.com/css3/a-guide-to-flexbox.html
有意见请留言。
如需转载请注明出处。