理解Flexbox:你需要知道的一切
这篇文章介绍了Flexbox模块所有基本概念,而且是介绍Flexbox模块的很好的一篇文章,所以这篇文章非常的长,你要有所准备。
学习Flexbox的曲线
@Philip Roberts在Twitter上发了一个推:

学习Flexbox可不是件很有趣的事情,因为它将挑战你所知道的CSS布局方面的知识。当然这也是非常正常的,因为一切知识都是值得学习的。
另外你要认值对待Flexbox。因为它是现代Web布局的主流方式之一,不会很快就消失。它也成为一个新的W3C标准规范。既然如此,那让我们张开双臂,开始拥抱它吧!
你将学习
我将带你先了解Flexbox的一些基础知识。我想这是开始尝试学习Flexbox的必经阶段。

学习基础知识是件很有意思的事情,更有意思的是可以通过学习这些基础理论知识,在实际的应用程序中使用Flexbox。
我将带您亲历很多“小知识点”之后,在文章末尾,使用Flexbox来做一个音乐应用程序的布局(UI界面布局)。

看上去是不是棒棒的?
在开始进入学习Flexbox构建音乐应用程序的布局之前,你还将需要了解Flexbox在响应式Web设计中所起的作用。
我将会把这一切都告诉你。
在你开始构建音乐应用程序界面之前,我将一起陪你做一些练习。这看起来可能很无聊,但这是让你彻底掌握Flexbox必经的过程,只有这样才能让你很擅长的使用Flexbox。
说了这么多的废话,那我们赶紧的开始吧!(难怪篇幅长,原来开始有这么的…(^_^))
简介
CSS在过去的几年里已发生了很大的变化。CSS中引入了设计师喜欢的filters、transitions和transforms等。但有些东西已经消失了,可是我们都渴望这些东西能一直存在。
使用CSS制作智能的、灵活的页面布局一直以来都是CSSer想要的,也有很人使用各种不同的CSS黑魔法去实现智能的页面布局。
我们总是不得不忍受float、display:table这些布局方式带来的痛苦。如果你完写过一段时间的CSS,你可能有相关体会。如果你没有写过CSS,那你是幸运的,在这也欢迎你来到CSS布局中一个更美好的世界中!
似乎设计师和前端开发人员的这次祈祷终于被上帝听到了。而且这一次,在很大的风格上做出了改变。现在我们可以抛弃老司机们常用的CSS布局的黑魔法。也可以和float以及display:table说拜拜。
是时候去拥抱一个更简洁的制作智能布局的现代语法。欢迎CSS Flexbox模块的到来。
Flexbox是什么
根据规范中的描述可知道,Flexbox模块提供了一个有效的布局方式,即使不知道视窗大小或者未知元素情况之下都可以智能的,灵活的调整和分配元素和空间两者之关的关系。简单的理解,就是可以自动调整,计算元素在容器空间中的大小。
这样听起来是不是太官方了,其实我也明白这种感觉。
如何开始使用Flexbox
这是每个人都会问的第一个问题,答案是比你预想的要简单得多。
开始使用Flexbox时,你所要做的第一件事情就是声明一个Flex容器(Flex Container)。
比如一个简单的项目列表,我们常常看到的HTML形式如下所示:
<ul> <!--parent element-->
<li></li> <!--first child element-->
<li></li> <!--second child element-->
<li></li> <!--third child element-->
</ul>
一眼就能看出来,这就是一个无序列表(ul)里有三个列表元素(li)。
你可以把ul称为父元素,li称为子元素。
要开始使用Flexbox,必须先让父元素变成一个Flex容器。
你可以在父元素中显式的设置display:flex或者display:inline-flex。就这么的简单,这样你就可以开始使用Flexbox模块。
实际是显式声明了Flex容器之后,一个Flexbox格式化上下文(Flexbox formatting context)就立即启动了。
告诉你,它不是像你想像的那么复杂。

使用一个无序列表(ul)和一群列表元素(li),启动Flexbox格式化上下文的方式如下:
/* 声明父元素为flex容器 */
ul {
display:flex; /*或者 inline-flex*/
}
给列表元素(li)添加一点基本样式,这里你可以看到发生了什么。
li {
width: 100px;
height: 100px;
background-color: #8cacea;
margin: 8px;
}
你将看到的效果如下图所示:

你可能没有注意到,但事实上已经发生了变化。现在已经是一个Flexbox格式化上下文。
记住,默认情况下,div在CSS中垂直堆栈的,也就是说从上到下排列显示,就像下图这样:

上面的图是你希望的结果。
然而,简单的写一行代码display:flex,你立即就可以看到布局改变了。
现在列表元素(li)水平排列,从左到右。就像是你使用了float一样。
Flexbox模块的开始,正如前面的介绍,在任何父元素上使用display:flex。
你可能不明白为什么这一变化就能改变列表元素的排列方式。但我可以负责任的告诉你,你深入学习之后就能明白。现在你只需要信任就足够了。
理解flex display是使用Flexbox的一个开始。还有一件事情,我需要提醒您注意。
一旦你显式的设置了display属性的值为flex,无序列表ul就会自动变成Flex容器,而其子元素(在本例中是指列表元素li)就变成了Flex项目。
这些术语会一次又一次的提到,我更希望你通过一些更有趣的东西来帮助你学习Flexbox模块。
我使用了两个关键词,我们把重点放到他们身上。了解他们对于理解后面的知识至关重要。
- Flex容器(Flex Container):父元素显式设置了display:flex
- Flex项目(Flex Items):Flex容器内的子元素

这些只是Flexbox模块的基础。
Flex容器属性
flex-direction || flex-wrap || flex-flow || justify-content || align-items || align-content

通过上面的内容,我们了解了一些基础知识。知道了Flex容器和Flex项目是什么,以及如何启动Flexbox模块。
现在是一个好好利用它们的时间了。
有设置一个父元素作为一个Flex容器,几个对齐属性可以使用在Flex容器上。
正如你的块元素的width设置了200px,有六种不同的属性可以用于Flex容器。
好消息是,定义这些属性不同于你以往使用过的任何一种方法。
flex-direction
flex-direction属性控制Flex项目沿着主轴(Main Axis)的排列方向。
它具有四个值:
/* ul 是一个flex容器 */
ul {
flex-direction: row || column || row-reverse || column-reverse;
}
简单点来说,就是flex-direction属性让你决定Flex项目如何排列。它可以是行(水平)、列(垂直)或者行和列的反向。
从技术上讲,水平和垂直在Flex世界中不是什么方向(概念)。它们常常被称为主轴(Main-Axis)和侧轴(Cross-Axis)。默认设置如下所示。

通俗的说,感觉Main-Axis就是水平方向,从左到右,这也是默认方向。Cross-Axis是垂直方向,从上往下。默认情况下,flex-direction属性的值是row。它让Flex项目沿着Main-Axis排列(从左向右,水平排列)。这就解释了本文开始部分时无序列表的表现效果。
尽管flex-direction属性并没有显式的设置,但它的默认值是row。Flex项目将沿着Main-Axis从左向右水平排列。

如果把flex-direction的属性值修改成column,这时Flex项目将沿着Cross-Axis从上到下垂直排列。不再是从左向右排列。

flex-wrap
flex-wrap属性有三个属性值:
ul {
flex-wrap: wrap || nowrap || wrap-reverse;
}
我将通过一个例子来解释如何使用flex-wrap属性。首先在前面的无序列表的HTML结构中多添加几个列表项li。
将Flex容器设置适合大小以适合放置更多的列表项目或者说让列表项目换行排列。这两种方式,你是怎么想的?
<ul> <!--parent element-->
<li></li> <!--first child element-->
<li></li> <!--second child element-->
<li></li> <!--third child element-->
<li></li>
<li></li>
<li></li>
</ul>
幸运的是,新添加的Flex项目刚好适合Flex容器大小。也就是Flex项目能刚好填充Flex容器。

再深入一点。
继续给Flex容器内添加Flex项目,比如说添加到10个Flex项目。这个时候会发生什么?

同样的,Flex容器还是能容纳所有的子元素(Flex项目)排列,即使浏览器出现了水平滚动条(当Flex容器中添加了很多个Flex项目,至使Flex容器的宽度大于视窗宽度)。
这是每一个Flex容器的默认行为。Flex容器会在一行内容纳所有的Flex项目。这是因为flex-wrap属性的默认值是nowrap。也就是说,Flex项目在Flex容器内不换行排列。
ul {
flex-wrap: nowrap; /*Flex容器内的Flex项目不换行排列*/
}
no-wrap不是不可改变的。我们可以改变。
当你希望Flex容器内的Flex项目达到一定数量时,能换行排列。当Flex容器中没有足够的空间放置Flex项目(Flex项目默认宽度),那么Flex项目将会换行排列。把它(flex-wrap)的值设置为wrap就有这种可能:
ul {
flex-wrap: wrap;
}
现在Flex项目在Flex容器中就会多行排列。
在这种情况下,当一行再不能包含所有列表项的默认宽度,他们就会多行排列。即使调整浏览器大小。
就是这样子。注意:Flex项目现在显示的宽度是他们的默认宽度。也没有必要强迫一行有多少个Flex项目。

除此之外,还有一个值:wrap-reverse。
是的,你猜对了。它让Flex项目在容器中多行排列,只是方向是反的。

flex-flow
flex-flow是flex-direction和flex-wrap两个属性的速记属性。
你还记得使用border的速记写法?border: 1px solid red。这里的概念是相同的,多个值写在同一行,比如下面的示例:
ul {
flex-flow: row wrap;
}

相当于:
ul {
flex-direction: row;
flex-wrap: wrap;
}
除了这个组合之外,你还可以尝试一些其它的组合。flex-flow: row nowrap,flex-flow: column wrap,flex-flow: column nowrap。
我相信你了解这些会产生什么样的效果,要不尝试一下。
justify-content
Flexbox模块真得很好。如果你仍然不相信它的魅力,那么justify-content属性可能会说服你。
justify-content属性可以接受下面五个值之一:
ul {
justify-content: flex-start || flex-end || center || space-between || space-around
}
justify-content属性又能给我们带来什么呢?提醒你一下,你是否还记得text-align属性。其实justify-content属性主要定义了Flex项目在Main-Axis上的对齐方式。
来看一个简单的例子,还是考虑下面这个简单的无序列表:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
添加一些基本样式:
ul {
display:flex;
border: 1px solid red;
padding: 0;
list-style: none;
background-color: #e8e8e9;
}
li {
background-color: #8cacea;
width: 100px;
height: 100px;
margin: 8px;
padding: 4px;
}
你将看到的效果是这样:

通过justify-content属性,可以让Flex项目在整个Main-Axis上按照我自己的欲望设置其对齐方式。
可能会有以下几种类型。
flex-start
justify-content的默认属性值是flex-start。
flex-start让所有Flex项目靠Main-Axis开始边缘(左对齐)。
ul {
justify-content: flex-start;
}

flex-end
flex-end让所有Flex项目靠Main-Axis结束边缘(右对齐)。
ul {
justify-content: flex-end;
}

center
和你预期的一样,center让所有Flex项目排在Main-Axis中间(居中对齐)。
ul {
justify-content: center;
}

space-between
space-between让除了第一个和最一个Flex项目的两者间间距相同(两端对齐)。
ul {
justify-content: space-between;
}

你注意到有什么不同?看看下图的描述:

space-around
最后,space-around让每个Flex项目具有相同的空间。
ul {
justify-content: space-around;
}

和space-between有点不同,第一个Flex项目和最后一个Flex项目距Main-Axis开始边缘和结束边缘的的间距是其他相邻Flex项目间距的一半。看看下图的描述:

千万不要觉得这些练习太多,这些练习可以帮助熟悉Flexbox属性的语法。也能更好的帮助你更好的理解它们是如何影响Flex项目沿着Main-Axis的对齐方式。
align-items
align-items属性类似于justify-content属性。只有理解了justify-content属性,才能更好的理解这个属性。
align-items属性可以接受这些属性值:flex-start || flex-end || center || stretch || baseline。
ul {
align-items: flex-start || flex-end || center || stretch || baseline
}
它主要用来控制Flex项目在Cross-Axis对齐方式。这也是align-items和justify-content两个属性之间的不同之处。
下面是不同的值对Flex项目产生的影响。不要忘记这些属性只对Cross-Axis轴有影响。
stretch
align-items的默认值是stretch。让所有的Flex项目高度和Flex容器高度一样。

flex-start
正如你所希望的flex-start让所有Flex项目靠Cross-Axis开始边缘(顶部对齐)。

flex-end
flex-end让所有Flex项目靠Cross-Axis结束边缘(底部对齐)。

center
center让Flex项目在Cross-Axis中间(居中对齐)。

baseline
让所有Flex项目在Cross-Axis上沿着他们自己的基线对齐。

结果看上去有点像flex-start,但略有不同。那“baseline”到底是什么呢?下图应该能帮助你更好的理解。

align-content
还记得前面讨论的wrap属性吗?我们在Flex容器中添加了更多的Flex项目。让Flex容器中的Flex项目多行排列。
align-content属性用于多行的Flex容器。它也是用来控制Flex项目在Flex容器里的排列方式,排列效果和align-items值一样,但除了baseline属性值。
像align-items属性一样,它的默认值是stretch。你现在应该熟悉这些值。那它又是如何影响Flex容器里的10个Flex项目多行排列方式。
stretch
使用stretch会拉伸Flex项目,让他们沿着Cross-Axis适应Flex容器可用的空间。
你看到的Flex项目间的间距,是Flex项目自身设置的margin值。

flex-start
之前你看到过flex-start。这次是让多行Flex项目靠Cross-Axis开始边缘。沿着Cross-Axis从上到下排列。因此Flex项目在Flex容器中顶部对齐。

flex-end
flex-end刚好和flex-start相反,让多行Flex项目靠着Cross-Axis结束位置。让Flex项目沿着Cross-Axis从下到上排列,即底部对齐。

center
你猜到了,center让多行Flex项目在Cross-Axis中间。在Flex容器中居中对齐。

这是Flex容器的最后一个属性。你现在知道如何使用各种Flex容器属性。你可以在工作中实践这些属性。
译者:大漠
