跨浏览器的Flexbox

本文由大漠根据的《Advanced cross-browser flexbox》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://dev.opera.com/articles/view/advanced-cross-browser-flexbox/,以及作者相关信息

——作者:

——译者:大漠

简介

CSS Flexible盒模型3又简称为Flexbox。摒弃我们传统上使用的一些hack和组件,Flexbox给网络的发展带来了很多正能量和兴奋济,让我们一起把复杂的网站布局变得简易和快速。早前在Flexbox: fast track to layout nirvana?一文中介绍了Flexbox的一些基础知识。在本文中,我将更进一步,借用Modernizr脚本库使用不同的样式做Flexbox在各浏览器下做一些差异化处理,为Flexbox在各浏览器下提供最佳展示水平。

如果你阅读《Flexbox: fast track to layout nirvana?》一文,对英文感觉吃力的话,你可以移动阅读翻译的中文版本《Flexbox——快速布局神器》。

——大漠

推出案例

在这篇文章中创建的例子,看起来如下图所示:

跨浏览器的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),但有多余的空间时,伸缩项目能扩大填补。当你扩展和收缩页面的时候看看会发生什么?

跨浏览器的Flexbox

接下来设置第二个<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

跨浏览器的Flexbox

一个没有媒体查询的响应式图像框。

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

上表显示了不同的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的其他工具:

  1. Flexplorer
  2. CSS Flexbox Please!
  3. Flexiejs

——大漠

添加简单的媒体查询实现宽屏和窄屏的布局

最后,为了解决宽屏和窄屏下的布局,我决定添加几个媒体查询。但注意怎么在媒体查询中添加这些代码,因为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

返回顶部