Flexbox完整指南- A Complete Guide to Flexbox

背景

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布局的主要思想。

flexbox

基本上,子元素要么根据主轴(main axis,从主轴开始到主轴结束 )排列或者交叉轴(从交叉轴开始到交叉轴结束)排列。

  • 主轴 - flex容器的主轴是flex子元素的首要排列方向。要注意的时,主轴并不一定是水平的;实际方向要根据flex-direction属性确定(后面详细说明)。
  • 主轴起点|主轴终点 - flex子元素在flex容器内从 主轴起点 到 主轴终点 排列。
  • 主轴尺寸 - 一个元素的主要尺寸要么是它的宽度(width)要么是它的高度(height)。这要取决于哪一个属性对着主轴方向。
  • 交叉轴 - 垂直于主轴方向的轴称之为交叉轴。它的方向取决于主轴方向。
  • 交叉轴起点|交叉轴终点 - Flex行被flex子元素填充,从交叉轴起点到交叉轴终点。
  • 交叉轴尺寸 - 一个元素的交叉轴尺寸要么是它的宽度(width)要么是它的高度(height)。这要取决于哪一个属性对着交叉轴方向。

译者注:交叉轴(cross-axis)也被翻译做侧轴、旁轴

flex容器的属性(flex container)

译者注:不同于常规布局,flex布局依赖于flex容器和flex子元素共同配合完成。所以要在flex容器上设定一些属性。

flex-container

display

这个属性定义了一个flex容器;可以设定为 inline(内联) 元素 或者 block(块级)元素。它给它的所有直接子元素提供了一个 flex 上下文(环境)。

//CSS
.container{
    display:flex; /* 或者 inline-flex */
}
  • 注意 CSS 列(columns)在 flex容器 上不起作用。
  • float、clear和vertical-align在伸缩项目上没有效果。

flex-direction

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-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-directionflex-wrap 属性的简洁表示(就像font之于 font-size、font-family、font-weight一样),同时定义了 flex容器 的主轴和交叉轴。 默认值是 row nowrap

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

justify-content

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

align-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

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)

flex-items

order

order
默认情况下,flex子元素以源代码中的顺序分布。但是, order 属性可以控制他们他们在 flex容器 中的表现。

//CSS
.item{
    order:<integer>; //默认是0;
}

flex-grow

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-shrinkflex-basis)是可选的。默认值是 0 1 auto

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

建议用属性缩写代替单独的属性。这个缩写会聪明地设置其他值。

align-self

align-self

该属性允许元素覆盖默认的对齐方式(或者 align-items 定义的对齐方式)。

参见 align-items 的解释来理解本属性可选的值。

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

注意 floatclearvertical-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

Flexbox at MDN

Flexbox at Opera

Diving into Flexbox by Bocoup

Mixing syntaxes for best browser support on CSS-Tricks

Flexbox by Raphael Goetter (FR)

Flexplorer by Bennett Feely

Bugs

Flexbox当然存在bug。我见过的关于这些bug的最好的集合是 Philip Walton 和 Greg Whitworth 的Flexbugs。这是一个开源的地方来对这些进行记录,我给出这个链接就好。

浏览器支持

flex的版本划分如下:

  • (new)表示最近的标准的语法(例如:display:flex;
  • (tweener)表示2011年版本的语法(例如:display:flexbox;
  • (old)表示最早的2009年的语法(例如:display:box;
chrome
21+(new)
20-(old)

有关如何混合多种语法达到最好的浏览器兼容效果,请参阅这两篇文章 CSS-tricksthis 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

有意见请留言。

如需转载请注明出处。

posted @ 2015-04-28 21:11 随心追梦 阅读(...) 评论(...) 编辑 收藏