原文地址

http://css-tricks.com/snippets/css/a-guide-to-flexbox/

译文不一定与原文内容完全相符,有我对其中的一些理解,但不会有太大的出入。

引言

Flexbox是一种更高效更灵活的布局方式,它可以让一些元素在一个容器里很容易的实现各种对齐以及控制这些元素之间的距离,即使这些元素的大小不固定(这也是它为什么叫flex的原因)。

其实Flex布局的主要思想是可以让容器去改变子元素的宽度、高度、顺序以及它们之间的距离等等(当然,这种布局方式针对不同的设备,不同分辨率都是起作用的)。Flex盒子会根据有效的空间去扩展或收缩元素。

比较重要的一点是,Flex盒子的布局方式与以前的盒子是有所区别的,比如说block元素是垂直排列,inline元素是水平排列,而Flex与方向是没有太大关系的。blockinline元素在默认的情况下,它们的的灵活性不是很高,比如说浏览器缩放时,手机屏幕旋转时等等。

基本知识

首先,Flexbox是一种布局方式,不只是一个单独的CSS属性而已,它是由好多的属性组成的。其中有一些属性是设置在Flexbox外层容器上的(父层),还有一些是设置在容器内部的元素上的。

普通元素的布局方式是按照标准流(block元素竖排,inline元素横排…)进行布局的,而Flex则有”自己的标准流”,请看下面这张来自W3C官网的图片,它描绘了Flex布局背后的基本信息:

flexbox

上图中对应的翻译为:

  • main axis-主轴
  • main size-主轴长度
  • cross axis-侧轴
  • cross size-侧轴长度
  • main start-主轴起点
  • main end-主轴终点
  • cross start-侧轴起点
  • cross end-侧轴终点
  • flex item-伸缩项目
  • flex container-伸缩容器

伸缩项目内部的伸缩项目将会依据 主轴 main axis(从main-startmain-end)或者侧轴(cross axis,从cross-startcross-end)。

  • 主轴:flex布局的主要依据,需要注意的是,这并不意味着flex布局是一种横向的布局方式。其实它是什么方向的表现形势取决于flex-direction属性(下面会说到)。
  • 主轴起点|主轴终点 :flex盒子里的子元素(flex items)会被旋转在main-startmain-end之间。
  • 主轴长度:伸缩项目在主轴方向的宽度或高度就是项目的主轴长度,这个长度则是由widthheight属性决定的。
  • 侧轴:与主轴互垂直的轴叫侧轴,所以它的方向是取决于主轴的方向的。
  • 侧轴起点|侧轴终点:伸缩行在侧轴的方向上只会被旋转在侧轴的起点和终点中。
  • 侧轴起点|侧轴终点:伸缩行在侧轴的方向上只会被旋转在侧轴的起点和终点中。
  • 侧轴长度:伸缩项目在侧轴方向的宽度或高度就是伸缩项目的侧轴长度,长度也取决于widthheight属性。

相关属性

display:flex|inline-flex;(该属性作用于伸缩容器)

这个属性就是定义一个伸缩容器,这时容器里的子元素就是一个个的伸缩项目。

display: other values | flex | inline-flex;

需要注意的是:

  • CSS的column属性对伸缩容器不起作用。
  • float,clearvertical-align对伸缩项目不起作用。

flex-direction(该属性作用于伸缩容器)

当这个属性设置后,主轴也就确定了,所以伸缩项目在伸缩窗口内的位置也就确定了。

flex-direction: row | row-reverse | column | column-reverse
  • row(默认):将伸缩项目从左向右排列
  • row-reverse:将伸缩项目从右向左排列
  • column:将伸缩项目从上向下排列
  • column-reverse:将伸缩项目从下向上排列

flex-wrap(该属性作用于伸缩容器)

该属性决定了伸缩容器是单行还是多行,还决定了侧轴的方向(也就是新的一行堆放的方向)。

flex-wrap: nowrap | wrap | wrap-reverse
  • nowrap(默认):单行,将伸缩项目从左向右排列
  • wrap:多行,将伸缩项目从左向右排列
  • wrap-reverse:多行,将伸缩项目从右向左排列

flex-flow(该属性作用于伸缩容器)

该属性是flex-directionflex-wrap的缩写方式。同时定义了伸缩容器的主轴和侧轴,默认是row nowrap

flex-flow: <‘flex-direction’> || <‘flex-wrap’>

justify-content(该属性作用于伸缩容器)

该属性会作用于主轴上的伸缩项目,该属性会在所有的伸缩项目的大小都确定后(浏览器解释计算出大小)才生效,当一行内所有伸缩项目不能伸缩或达到最大长度时,该属性会对多余空白空间进行分配,当伸缩项目溢出某一行时,该属性也会相应的调整伸缩项目的对齐方式。

justify-content: flex-start | flex-end | center | space-between | space-around
  • flex-start(默认):伸缩项目会向一行的起始位置靠齐。
  • flex-end:伸缩项目会向一行的结束位置靠齐。
  • center:伸缩项目会向一行的中间靠齐。
  • space-between:伸缩项目会平均分布在一行内,第一个伸缩项目会在一行的开头位置,最后一个伸缩项目会在一行的结束位置。另外,如果没有多余的空间,那么该值会等效于flex-start
  • space-around:伸缩项目会平均分布在一行内,并且两端多余空间的大小是其它多余空间大小的一半(也就是各伸缩项目之间空间的一半)。另外,如果没有多余空间的话,那么该值会等同于center
justify-contetnt

align-items(该属性作用于伸缩容器)

该属性是控制一行上伸缩项目在侧轴方向上的对齐方式,和justify-content类似。

align-items: flex-start | flex-end | center | baseline | stretch
  • flex-start:伸缩项目在侧轴起点的那一边向侧轴的起点靠齐。
  • flex-end:伸缩项目在侧轴终点的那一边向侧轴的终点靠齐。
  • center:伸缩项目在侧轴上居中。
  • baseline:伸缩项目将会以它们的基线对齐为准。
  • stretch(默认):伸缩项目会自动伸缩充满整个伸缩容器(当然,加了max|min-width|height后除外)。
align-items

align-content(该属性作用于伸缩容器)

如果伸缩容器的侧轴上还有多余空间时,那么该属性会调整伸缩行在伸缩容器内的对齐方式,与justify-content类似。

注意:当只有一个伸缩行的时候,这个属性是不起作用的!

align-content: flex-start | flex-end | center | space-between | space-around | stretch
  • flex-start:在侧轴上,伸缩行的第一行靠紧侧轴的开始点,后面的行依次紧紧跟随。
  • flex-end:在侧轴上,伸缩行的最后一行靠紧侧轴的终点,前面的行依次紧紧跟随。
  • center:在侧轴上,伸缩行居中对齐。
  • space-between:在侧轴上,伸缩行在伸缩容器内平均分布,其中第一行侧轴起点的一边靠紧侧轴起点,最后一行侧轴终点的一边靠紧侧轴终点。
  • space-around:在侧轴上,伸缩行在伸缩容器内平均分布,起始两行的两边会留有伸缩行之间空格的一半的空间。
  • stretch(默认):伸缩行会在伸缩容器内自动伸缩,充满整个伸缩容器。
align-content

order(该属性作用于伸缩项目)

默认情况下,伸缩项目的排列顺序是依据本身的书写位置来的,但添加了order后,伸缩项目则会根据order的值进行排列。

order: <integer>

flex-grow(该属性作用于伸缩项目)

该属性只会在伸缩容器内有多余空间的情况下才会起作用。从属性名就可以看出,它是控制伸缩项目伸展程度的。该属性的值是一个没有单位且大于等于0的数字(默认就是0),当伸缩项目间有多余空间的时候,那么伸缩盒子会根据所设置的数值进行分配比例。例如,一个伸缩容器内有两个伸缩项目,第一个伸缩项目添加flex-grow:1,第二个伸缩项目添加flex-grow:5,那么,它们的尺寸比就是1比5,中间不再有空格。如果值设置相等的话,那么它们会扩展成一样的大小。

flex-grow: <number> (default 0)

flex-shrink(该属性作用于伸缩项目)

对伸缩项目添加该属性后,会在必要的时候对伸缩项目进行收缩,属性值不能为负数,默认为1。

flex-shrink: <number> (default 1)

flex-basis(该属性作用于伸缩项目)

该属性是在计算出可用剩余空间之前给伸缩项目设置默认长度。

flex-basis: <length> | auto (default auto)

flex(该属性作用于伸缩项目)

这是flex-grow,flex-shrinkflex-basis的缩写形势。其中第二和第三个属性(flex-shrink,flex-basis)是可选的。默认值是0 1 auto

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

flex属性几种常见值的意思:

  • flex:0 auto,flex:initialflex: 0 1 auto相同
  • flex:autoflex:1 1 auto相同
  • flex:noneflex:0 0 auto相同
  • flex:正数flex:1 0px相同

align-self(该属性作用于伸缩项目)

前面说过align-items,它是添加在伸缩容器上的,用于伸缩项目在一行上侧轴方向的对齐方式 ,而align-self则是添加到伸缩项目上的,添加它以后,会把父层的align-items属性的效果替换掉。

align-self: auto | flex-start | flex-end | center | baseline | stretch

示例

让我们来做一些简单的例子,在使用了flexbox布局的话,以前的一些比较常见并且较难解决的问题可以非常容易的就解决了,比如说将一个元素绝对居中。

.parent {
  display: flex;
  height: 300px; /* Or whatever */
}

.child {
  width: 100px;  /* Or whatever */
  height: 100px; /* Or whatever */
  margin: auto;  /* Magic! */
}

上面的代码是给伸缩项目添加了margin:auto,所以它会在伸缩容器内居中(水平和垂直方向).

译者:为什么不直接用justify-content:center;align-items:center;呢?我试了下,也是可以绝对居中的:

.parent {
  display: flex;
  height: 300px; /* Or whatever */
  background:skyblue;
  align-items:center;
  justify-content:center;
}

See the Pen flex perfect centering by blwoosky (@blwoosky) on CodePen.

再试试其它更多的属性,这里有6个列表项。为了美观,6个列表项都被设置成了固定大小,当然也是可以让它们自动大小的,我们想让它在不同的分辨率下在水平方向上都会自动排列(不使用media queries)。

.flex-container {
  /* We first create a flex layout context */
  display: flex;
  
  /* Then we define the flow direction and if we allow the items to wrap 
   * Remember this is the same as:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;
  
  /* Then we define how is distributed the remaining space */
  justify-content: space-around;
}

所有的东西都只是样式写出来的,下面是效果:

See the Pen Demo Flexbox 1 by Hugo Giraudel (@HugoGiraudel) on CodePen.

再举个例子,比如网站的最顶部有一个右对齐的导航,但我们想让它在中等大小屏幕上居中显示,在小屏幕设备上显示成一列。

/* Large */
.navigation {
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-end;
}

/* Medium screens */
@media all and (max-width: 800px) {
  .navigation {
    justify-content: space-around;
  }
}

/* Small screens */
@media all and (max-width: 500px) {
  .navigation {
    flex-direction: column;
  }
}

See the Pen Demo Flexbox 2 by Hugo Giraudel (@HugoGiraudel) on CodePen.

现在,让我们来试试用flex做一个较简单的页面。我们想要做一个手机站,但是在不是手机上访问的时候,我们把它设置成3列的布局,头部和底部都是百分百宽的,并且主体内容的3列排列顺序是不固定的。

.wrapper {
  display: flex;
  flex-flow: row wrap;
}

/* We tell all items to be 100% width */
.header, .main, .nav, .aside, .footer {
  flex: 1 100%;
}

/* We rely on source order for mobile-first approach
 * in this case:
 * 1. header
 * 2. nav
 * 3. main
 * 4. aside
 * 5. footer
 */

/* Medium screens */
@media all and (min-width: 600px) {
  /* We tell both sidebars to share a row */
  .aside { flex: 1 auto; }
}

/* Large screens */
@media all and (min-width: 800px) {
  /* We invert order of first sidebar and main
   * And tell the main element to take twice as much width as the other two sidebars 
   */
  .main { flex: 2 0px; }
  .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.

相关属性

其它参考资料

浏览器兼容性问题

  • (modern)指支持W3C官方给出的标准语法(比如:display:flex;)
  • (hybird)指支持2011年出现各厂商一些零散的不统一的语法(比如:display:flexbox;)
  • (old)指支持2009年出现的一些较旧的语法(比如:display:box;)
Chrome Safari Firefox Opera IE Android iOS
21+ (modern)
20- (old)
3.1+ (old) 2-21 (old)
22+ (new)
12.1+ (modern) 10+ (hybrid) 2.1+ (old) 3.2+ (old)

黑莓浏览器10+版本支持新的写法。

关于解决各杂七杂八浏览器兼容性问题,请看以下两篇文章:

这里有一个简单的 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);
}