原文:A Complete Guide to Flexbox
做者:CHRIS COYIER
译者:Shelley Lee
本文同时发布于知乎专栏:前端指南
转载需提早联系译者,未经容许不得转载。css
Flexbox 布局(也叫Flex布局,弹性盒子布局)模块目标在于提供一个更有效地布局、对齐方式,而且可以使父元素在子元素的大小未知或动态变化状况下仍然可以分配好子元素之间的间隙。html
Flex布局的主要思想是使父元素可以调节子元素的高度、宽度和排布的顺序,从而可以最好地适应可用布局空间(可以适应不一样的设备和不一样大小的屏幕)。设定为flex布局的父元素(容器)可以放大子元素使之尽量填充可用空间,也能够收缩子元素使之不溢出。前端
最重要的是,与传统布局中块状元素按照垂直方向摆放,行内元素按照水平方向摆放相比,flex布局是无方向的。传统布局在应对大型复杂的布局时缺少灵活性,特别是在改变方向、改变大小、伸展、收缩等等方面。css3
注: Flex 布局比较适合小规模的布局,Gird布局面向更大规模的布局。git
Flex布局是一个完整的模块而不是一个单独的属性,它包括了完整的一套属性。其中有的属性是设置在容器(container,也能够叫作父元素,称为flex container
)上,有的则是设置在容器的项目上(item,也能够叫作子元素,称为flex items
)上。github
译者注:因为item译成项目不够直观和形象,如下统一用父元素指代container,子元素指代item。web
若是咱们能够说传统布局是创建在块状元素垂直流和行内元素水平流上的,那么flex布局就是创建在"flex-flow方向"上的,经过下图解释flex布局的主要思想。shell
在flex布局中,子元素要么按照主轴也就是main axis
(从main-start
到main-end
)排布,要么按照交叉轴,也就是cross axis
(从cross-start
到cross-end
)排布。浏览器
下面介绍几个概念:app
__main axis__: Flex 父元素的主轴是指子元素布局的主要方向轴,注意主轴不必定是水平的,它由属性flex-direction
来肯定主轴是水平仍是垂直的(后面会介绍)。
__main-start|main-end__: 分别表示主轴的开始和结束,子元素在父元素中会沿着主轴从main-start
到main-end
排布。
__main size__: 单个项目占据主轴的长度大小。
__cross axis__: 交叉轴,与主轴垂直。
__cross-start|cross-end__: 分别表示交叉轴的开始和结束。子元素在交叉轴的排布从cross-start
开始到cross-end
。
__cross size__: 子元素在交叉轴方向上的大小。
属性分做用于父元素的属性和做用于子元素的属性两部分介绍。
用来定义父元素是一个 flex布局容器。若是设置为flex
则父元素为块状元素,设置为inline-flex
父元素呈现为行内元素。
.container { display: flex; /* or inline-flex */ }
flex-direction
定义flex布局的主轴方向。flex布局是单方向布局,子元素主要沿着水平行或者垂直列布局。
.container { flex-direction: row | row-reverse | column | column-reverse; }
row
: 行方向,flex-direction
的默认值,在ltr
(left to right, 从左到右)排版方式下从左到右排列,在rtl
(right to left, 从右到左)排版方式下从右到左排列。
row-reverse
: 行反方向,在ltr
中从右向左,在rtl
中从左到右。
column
: 列方向,与row
类似,只是从上到下。
column-reverse
: 列反方向,与row-reverse
类似,只是从下岛上。
默认状况下,flex布局中父元素会把子元素尽量地排在同一行,经过设置flex-wrap
来决定是否容许子元素这行排列。
.container{ flex-wrap: nowrap | wrap | wrap-reverse; }
nowrap
: 不折行,默认值,全部的子元素会排在一行。
wrap
: 折行,子元素会从上到下根据需求折成多行。
wrap-reverse
: 从下向上折行,子元素会从下岛上根据需求折成多行。
这里有一些可视化的示例。
flex-flow
是flex-direction
和flex-wrap
属性的缩写形式。默认值是row,nowrap
。
flex-flow: <‘flex-direction’> || <‘flex-wrap’>
justify-content
属性定义了子元素沿主轴方向的对齐方式,用来当子元素大小最大的时候,分配主轴上的剩余空间。也能够当子元素超出主轴的时候用来控制子元素的对齐方式。
flex-start
: 默认值,朝主轴开始的方向对齐。
flex-end
: 朝主轴结束的方向对齐。
center
: 沿主轴方向居中。
space-between
: 沿主轴两端对齐,第一个子元素在主轴起点,最后一个子元素在主轴终点。
space-around
: 沿主轴子元素之间均匀分布。要注意的是子元素看起来间隙是不均匀的,第一个子元素和最后一个子元素离父元素的边缘有一个单位的间隙,但两个子元素之间有两个单位的间隙,由于每一个子元素的两侧都有一个单位的间隙。
.container { justify-content: flex-start | flex-end | center | space-between | space-around; }
align-items
定义了子元素在交叉轴方向的对齐方向,这是在每一个子元素仍然在其原来所在行的基础上所说的。能够看做是交叉轴上的justify-content
属性;
.container { align-items: flex-start | flex-end | center | baseline | stretch; }
flex-start: 按照交叉轴的起点对齐。
flex-end: 按照交叉轴的终点对齐。
center: 沿交叉轴方向居中。
baseline: 按照项目的第一行文字的基线对齐。
stretch: 默认值,在知足子项目所设置的min-height
、max-height
、height
的状况下拉伸子元素使之填充整个父元素。
align-content
是当父元素所包含的行在交叉轴方向有空余部分时如何分配空间。与justify-content
在主轴上如何对单个子元素对齐很类似。
注意:当只有一行的时候,该属性并不起做用。
.container { align-content: flex-start | flex-end | center | space-between | space-around | stretch; }
译者注:该属性中的六个属性值与
justify-content
中的六个属性意思类似,不一样之处在于justify-content
沿主轴方向的做用于单个子元素,而align-content
沿交叉轴方向做用于行。遂再也不赘述各属性值含义。译者注:注意
align-items
和align-content
的区别,前者是指在单行内的子元素对齐方式,后者是指多行之间的对齐方式。
display: flex|inline-flex; flex-direction: row | row-reverse | column | column-reverse; flex-wrap: nowrap | wrap | wrap-reverse; flex-flow: <‘flex-direction’> || <‘flex-wrap’>; justify-content: flex-start | flex-end | center | space-between | space-around; align-items: flex-start | flex-end | center | baseline | stretch; align-content: flex-start | flex-end | center | space-between | space-around | stretch;
默认状况下,子元素按照代码书写的前后顺序布局,但order
属性能够更改子元素出现的顺序。
.item { order: <integer>; }
译者注:
order
的默认值为0;子元素的order
值越小,布局越排在前面,参考例图理解。
flex-grow
规定在空间容许的状况下,子元素如何按照比例分配可用剩余空间。若是全部的子元素的属性都设定为1
,则父元素中的剩余空间会等分给全部子元素。若是其中某个子元素的flex-grow
设定为2,则在分配剩余空间时该子元素将得到其余元素二倍的空间(至少会尽力得到)。
.item { flex-grow: <number>; /* default 0 */ }
注:flex-grow
不接受负值。
译者注:默认值为
0
,意味着即便有剩余空间,各子元素也不会放大。
与flex-grow
属性相似,flex-shrink
定义了空间不足时项目的缩小比例。
.item { flex-shrink: <number>; /* default 1 */ }
注: flex-shrink
不接受负值。
译者注:
flex-shrink
默认值为1
, 当全部子元素都为默认值时,则空间不足时子元素会同比例缩小。若是其中某个子元素的flex-shrink
值为0,则空间不足时该子元素并不会缩小。若是其中某个子元素的flex-shrink
值为2时,则空间不足时该子元素会以二倍速度缩小。
flex-basis
定义了在计算剩余空间以前子元素默认的大小。能够设置为某个长度(e.g. 20%, 5rem, etc.)或者关键字。关键字auto
意味着子元素会按照其原本的大小显示。关键字content
意味着根据内容来肯定大小——这个关键字到目前没有被很好地支持,因此测试起来比较困难,与content
的相似的关键字还有max-content
, min-content
, fit-content
。
.item { flex-basis: <length> | auto; /* default auto */ }
若是设置为0, 则子元素内容周围的空隙不会根据flex-grow
按比例分配,若是设置为auto
,则子元素周围额外的空袭会根据flex-grow
按照比例分配,以下图:
flex
是flex-grow
、flex-shrink
、flex-basis
三个属性的缩写。其中第二个和第三个参数(flex-grow
,flex-basis
)是可选的。默认值为0 1 auto
。
.item { flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] }
推荐使用缩写形式而不是单独地设置每个属性,缩写形式中会智能地计算出相关值。
经过设置某个子元素的align-self
属性,能够覆盖align-items
所设置的对齐方式。属性值与align-items
中的意义相同,再也不赘述。
.item { align-self: auto | flex-start | flex-end | center | baseline | stretch; }
注:float
,clear
和vertical-align
对flex子元素没有任何影响。
咱们从一个很是很是简单的例子开始,解决一个咱们常常会遇到的问题:水平垂直居中。若是使用flex布局会很是简单。
.parent { display: flex; height: 300px; /* 随意设定大小 */ } .child { width: 100px; /* 随意设定大小,比父元素要小 */ height: 100px; /* 同上 */ margin: auto; /* 见证奇迹的时刻 */ }
这个主要缘由是,在flex布局的父元素中设置margin
为auto
会自动吸取额外的空间,因此设置水平垂直的margin
都为auto
会使子元素在水平垂直方向上都完美居中。
如今咱们考虑用更多的属性。考虑有6个子元素,有固定的大小,可是咱们但愿他们可以在改变浏览器宽度的时候仍然能够在水平轴上完美地显示(注意在不使用媒体查询的前提下)。
.flex-container { /* 首先咱们先建立一个flex布局上下文 */ display: flex; /* 而后咱们定义flex方向和是否容许子元素换行 * 注意这与如下代码等价: * flex-direction: row; * flex-wrap: wrap; */ flex-flow: row wrap; /* 而后咱们定义在剩余空间上子元素如何排布 */ justify-content: space-around; }
完成。剩下的就是一些其余样式如颜色的设置了。
改变浏览器大小,看看布局会有什么变化吧!
让咱们再尝试一些别的东西。假设咱们有一个向右对齐的导航栏在咱们网页的最上端,可是咱们但愿它在中屏上显示时为居中,在小屏上显示为单列。一样使用flex布局,实现起来会很简单。
/* 大屏 */ .navigation { display: flex; flex-flow: row wrap; /* 这里设置对齐主轴方向的末端 */ justify-content: flex-end; } /* 中屏 */ @media all and (max-width: 800px) { .navigation { /* 当在中屏上,设置居中,并设置剩余空间环绕在子元素左右 */ justify-content: space-around; } } /* 小屏 */ @media all and (max-width: 500px) { .navigation { /* 在小屏上,咱们不在使用行做为主轴,而以列为主轴 */ flex-direction: column; } }
改变浏览器大小,看看布局会有什么变化吧!
咱们经过灵活使用flex布局尝试一些更好玩的布局。来作一个移动优先的3列布局并带有全屏宽的header和footer。
.wrapper { display: flex; flex-flow: row wrap; } /* 咱们要告诉全部的子元素宽度 100% */ .header, .main, .nav, .aside, .footer { flex: 1 100%; } /* 移动优先依赖于源代码默认的渲染顺序 * in this case: * 1. header * 2. nav * 3. main * 4. aside * 5. footer */ /* 中屏 */ @media all and (min-width: 600px) { /* 咱们要告诉两边的sidebar共享一个行 */ .aside { flex: 1 auto; } } /* 大屏幕 */ @media all and (min-width: 800px) { /* 经过order设定各个面板的渲染顺序 * 告诉主要面板元素占用侧栏两倍的空间 */ .main { flex: 2 0px; } .aside-1 { order: 1; } .main { order: 2; } .aside-2 { order: 3; } .footer { order: 4; } }
改变浏览器大小,看看布局会有什么变化吧!
Flex布局须要一些浏览器前缀来最大力度地兼容大多数的浏览器。Flex布局的前缀不仅是在属性前面添加浏览器前缀,不一样浏览器下的属性名和属性值都不一样,这是由于Flexbox布局的标准一直在变,一共有old, tweener, new 三个版本。
可能处理前缀的最好方法是使用新的语法书写CSS并经过Autoprefixer运行CSS,可以很好地处理这个问题。
另外,这里有一个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 bug总结是Philip Walton 和 Greg Whitworth的Flexbugs,是开源的,你能够在上面跟踪动态。
首先看一下Flex布局的三个版本
(new)是指标准中最近的语法(e.g. display:flex;
)。
(tweener)是指2011年之后非官方的临时版本(e.g. display:flexbox;
)。
(old)是指2009年之后的旧语法(e.g. display:box;
)
Blackberry browser 10+ 支持新语法。
更多混合使用语法达到最佳浏览器兼容,能够参考this article (CSS-Tricks)或者this article (DevOpera)
网上有很多flex相关教程,但当我看到CHRIS COYIER的这篇文章时,不由被其详尽所震撼,最近也在撰写布局相关的文章,故产生了翻译此文的想法。翻译过程当中尽可能保持原文原貌,部分地方作了小幅调整以便更加符合中文思惟。文中图片均来源于原文。水平有限,若有误漏之处,还请读者不吝赐教。最后但愿此文能给读者带去帮助。
更多讨论请到180251611