跨浏览器的Flexbox
本文由大漠根据Chris Mills的《Advanced cross-browser flexbox》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://dev.opera.com/articles/view/advanced-cross-browser-flexbox/,以及作者相关信息
——作者:Chris Mills
——译者:大漠
简介
CSS Flexible盒模型3又简称为Flexbox。摒弃我们传统上使用的一些hack和组件,Flexbox给网络的发展带来了很多正能量和兴奋济,让我们一起把复杂的网站布局变得简易和快速。早前在Flexbox: fast track to layout nirvana?一文中介绍了Flexbox的一些基础知识。在本文中,我将更进一步,借用Modernizr脚本库使用不同的样式做Flexbox在各浏览器下做一些差异化处理,为Flexbox在各浏览器下提供最佳展示水平。
如果你阅读《Flexbox: fast track to layout nirvana?》一文,对英文感觉吃力的话,你可以移动阅读翻译的中文版本《Flexbox——快速布局神器》。
——大漠
推出案例
在这篇文章中创建的例子,看起来如下图所示:
图片最终布局示例。
这个示例包含了多个伸缩容器(flexbox container)。如果你愿意,可以点击示例查看,阅读或探索更详细的代码。
整体布局
示例网站的基本布局是这样的:
<section> <nav></nav> <article></article> <article></article> </section>
<section>设置为一个伸缩容器,代码如下所示:
section {
display: -ms-flexbox;
-ms-box-orient: horizontal;/*IE10中显不一行,类似于flex-direction:row功能*/
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
注:从2011年到Opera和Chrome提供的最新规范,由于IE10目前支持不同的flexbox语法,在IE10中设置特定的属性。Firefox和其他的webkit内核浏览器(如Safari)支持一个更旧版本的flexbox语法(2009),这使用flexbox更糟糕。除此之外,Modernizr报告IE10支持现代flexbox的语法,尽管它他还没有用,因此我们需要使用老的语法来处理IE10下的flexbox效果,而不是使用Modernizr规则来做IE10的兼容。详细的可以看下文,你可以获取更多的细节介绍。
让他们都在同一水平流上,但<nav>使用下面的规则,迫使其在单独的一行中显示:
nav {
padding: 1rem;
-webkit-flex: 1 100%;
-moz-flex: 1 100%;
-ms-flex: 1 100%;
flex: 1 100%;
}
设置“flex-basis”为100%,使用其宽度和父容器的宽度一样,同时迫使其他伸缩项目到新的一行。<article>的“flex-grow”的值设置如下:
article:nth-of-type(1) {
-webkit-flex: 2;
-moz-flex: 2;
-ms-flex: 2;
flex: 2;
}
article:nth-of-type(2) {
-webkit-flex: 3;
-moz-flex: 3;
-ms-flex: 3;
flex: 3;
}
使他们在主轴点有一定比例的空间——第一个<article>占40%,也就是宽度的五分之二;第二个<article>(也就是图片容器)占60%,也就是宽度的五分之三。这是值得记住——这个比例是只有在同一线上的伸缩项目具有,并非所有伸缩项目都具有的比例。
注:“flex-basis”是一个收缩基准值,首先用在伸缩项目上,在那之后主轴剩余的空间会根据每个伸缩项目的“flex-grow”伸缩比率来划分给每个伸缩项目,分配主轴的剩余空间。当“flex-grow”没有显式的设置值时,它的默认值为“1”。为了更好的了解他是如何工作的原理,你可以阅读flexbox模块中的flex部分,或者阅读《Flexbox——快速布局神器》这篇文章里面有关于flex的内容介绍。
伸缩项目
当你设置了一个元素为伸缩容器的时候,它只会影响他的子元素,而不会进一步的影响他的后代元素。但是没有什么可以阻止你为他们的后代设置为伸缩项目,使用一些布局变得复杂化。很简单,在这里,我把<nav>设置为伸缩容器,我可以让他居中对齐,而且不必担心容器的宽度或视窗的宽度大小。
nav {
display: -ms-flexbox;
-ms-box-orient: horizontal;
-ms-box-pack: center;/*ie10水平居中*/
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
/*水平居中*/
-webkit-justify-content: center;
-moz-justify-content: center;
-ms-justify-content: center;
justify-content: center;
}
接着再把<ul>设置为伸缩容器,保证他的子元素li能居中,代码如下所示:
nav ul {
text-align: center;
display: -ms-flexbox;
-ms-box-orient: horizontal;
-ms-box-pack: center;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-justify-content: center;
-moz-justify-content: center;
-ms-justify-content: center;
justify-content: center;
width: 80%;
}
nav a {
width: 100%;
}
我还添加了一些属性来解决导航菜单项的外观。我希望<ul>不完全拉伸穿过屏幕,并且让所有文本居中显示,所以我设置了一个"width:80%"和"text-align:center"。同时给链接设置了宽度为100%,用来确保链接跨整个列表项宽度。
接下来是神奇的时刻。在这一点上,列表项看起来有眯重叠和奇怪,而用当他们开始包装时看起来有点笨。没有使用媒体查询实现一个响应式的菜单,看上去很酷,那么我们需要下面的代码来实现:
nav ul li {
margin: 0 1.5rem;
-webkit-flex: auto;
-moz-flex: auto;
-ms-flex: auto;
flex: auto;
min-width: 5rem;
}
在这里,我给列表项目设置了一个margin,让他们有一定的空间,给他们设置了一个min-width,并且将"flex"设置为“auto”。这是flex的一个特殊的值,可以让伸缩项目具有一个min-width的值,当没有多余的空间的时候,让伸缩项目保持一个常数大小(min-width),但有多余的空间时,伸缩项目能扩大填补。当你扩展和收缩页面的时候看看会发生什么?

接下来设置第二个<article>,并设置里面每个段落(包括段落里的img):
article:nth-of-type(2) {
display: -ms-flexbox;
-ms-box-orient: horizontal;
-ms-box-pack: center;
-ms-box-align: center;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: inline-flex;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-justify-content: center;
-moz-justify-content: center;
-ms-justify-content: center;
justify-content: center;
-webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
align-items: center;
-webkit-align-content: flex-start;
-moz-align-content: flex-start;
-ms-align-content: flex-start;
align-content: flex-start;
}
article p {
margin: 0.5rem;
-webkit-flex: 1 20rem;
-moz-flex: 1 20rem;
-ms-flex: 1 20rem;
flex: 1 20rem;
}
article p img {
display: block;
width: 100%;
border: 1px solid black;
}
在这里给他们设置了个固定的flex-basis值,所以他们会根据每行的数量增加和减少自己的宽度(如下图所示,没有使用媒体查询),并且会使用每一项,和每一项里面的内容水平垂直居中显示。



一个没有媒体查询的响应式图像框。
Flexbox反馈
支持Flexbox的浏览器有Webkite内核浏览器、Presto-based Opera、Firefox(即将),要真正支持主流浏览器将还需要一段时间。这意味着,如果我们想使用flxbox还需要选择一些备案方法。2009年开始一些浏览器(老的webkit、firefox)支持老版的Flexbox语法。奇怪的是IE10从2011后既支持老的语法又支持新的语法。值得庆幸的是Modernizr脚本库使用“flexbox”和“flexbox-legacy”标记能检测出Flexbox的现代语法和Flexbox旧的语法。实际上它并不支持这两种——它支持一个介于这两者之间的一种语法。这就是为什么我们一直在IE10中把代码写在CSS中,而不是使用Modernizr代码块,你将在后面的文章介绍中可以看到。
注:截至2013年04月会,已经有讨论如何处理Modernizr中Flexbox在IE10中检测问题。
下面的表总结了Flexbox最新语法和2009年、2011年等效的混合语法:

上表显示了不同的flexbox语法支持跨不同的浏览器,对不同属性的等价物。
注:从2009年的规范"box-lines"属性看上去等同于“flex-wrap”,但不幸的是,这个并不支持混合语法的浏览器。
所以,我在示例中添加了以下代码,用来实现支持flexbox混合写法,但不支持flexbox的浏览器的flebox效果:
.no-flexbox section {
display: -webkit-box;
display: -moz-box;
-webkit-box-orient: horizontal;
-moz-box-orient: horizontal;
}
.no-flexbox nav {
padding: 1rem;
width: 20%;
}
.no-flexbox article {
-webkit-box-flex: 1;
-moz-box-flex: 1;
}
.no-flexbox article p {
float: left;
}
.no-flexbox article img {
display: block;
width: 200px;
}
然后在样式中加入不支持flexbox,甚至不支持混合flexbox语法浏览器的兼容样式代码:
.no-flexbox-legacy nav, .no-flexbox-legacy article {
float: left;
}
.no-flexbox-legacy nav {
width: 20%;
}
.no-flexbox-legacy article {
width: 36%;
}
.no-flexbox article img {
float: left;
}
注:一个用来生成跨浏览器的flexbox代码,并且可以帮你了解不同浏览器使用语法的在线工具Flexy Boxes。
Flexbox在线生成工具
在70+ 优秀的前端工具中收录了类似于Flexy Boxes在线生成Flexbox的其他工具:
——大漠
添加简单的媒体查询实现宽屏和窄屏的布局
最后,为了解决宽屏和窄屏下的布局,我决定添加几个媒体查询。但注意怎么在媒体查询中添加这些代码,因为Flexbox天生就是创建响应式布局的神器。
首先在支持混合语法上写一些代码来解决响应式效果:
@media all and (max-width: 600px) {
h1 {
font-size: 5rem;
}
.no-flexbox section {
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
}
.no-flexbox nav {
width: 100%;
margin-left: -3rem;
}
.no-flexbox nav a, .no-flexbox nav ul, .no-flexbox nav li {
width: 100%;
}
}
接下来,一个现代flexbox修复,没有在所有的浏览器,在小屏幕宽度。
@media all and (max-width: 480px) {
article:nth-of-type(1) {
-webkit-flex: 1 100%;
-moz-flex: 1 100%;
-ms-flex: 1 100%;
flex: 1 100%;
}
body {
min-width: 320px;
}
nav ul {
width: 100%;
}
.no-flexbox-legacy nav, .no-flexbox-legacy article {
float: none;
}
.no-flexbox-legacy nav, .no-flexbox-legacy article {
width: 100%;
}
}
最后用媒体查询给大多少屏幕情况下设置一个居中效果:
@media all and (min-width: 1100px) {
section {
width: 1100px;
margin: 0 auto;
}
}
总结
此时是有限度的使用Flexbox,当都使用同一种方式支持现代浏览器的时候,Flexbox才会变得更加简易。到现在为止,更有效果的支持,只是一些简单的效果,单行的可以用flexbox,对于多行的在混合语法中就无法得到浏览器的支持。因为它的标准,我的示例运行的很正常,尽管混合语法的flexbox不如现代flexbox布局。另一个有趣的问题是,Firefox好像不支持居中,后来只好使用"margin: 0 auto"来实现(safari下支持居中)。
对于flexbox的一些简单的使用,在现代浏览器(Chrome、Firefox、Safari、Opera Presto 12.1+,IE10+,IOS和Android)可以得到很好的支持。
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
如需转载烦请注明出处:
英文原文:http://dev.opera.com/articles/view/advanced-cross-browser-flexbox
中文译文:http://www.w3cplus.com/css3/advanced-cross-browser-flexbox.html




