原文:https://dev.opera.com/articles/advanced-cross-browser-flexbox/
介绍
CSS灵活盒模块级3 -简称Flexbox-它为web开发带来了很多的动力和一些非常令人兴奋的可能性,使我们能够在一些复杂的站点布局很容易和迅速,摒弃一些不合逻辑的hacks和组装件我们传统上使用。我在文章Flexbox中处理了Flexbox的基础知识:快速布局必杀技?在本文中,我将进一步讨论一个更高级的示例,并使用Modernizr为具有不同Flexbox支持级别的浏览器提供不同的样式,从而提供当前可用的最佳跨浏览器支持级别。
介绍这个例子
我为本文构建的示例如图1所示:
图1:最终布局示例的图像
其中包含多个级别的Flexbox。如果您愿意,可以实时查看示例,并继续阅读以更详细地探索代码。
整体布局
该网站的基本布局如下:
<section>
<nav></nav>
<article></article>
<article></article>
</section>
将<section>
设置为display,就像这样的弹性盒:
section {
display: -ms-Flexbox;
-ms-box-orient: horizontal;
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;
}
注意:规则顶部指定了不同的IE特定属性,因为IE10目前支持不同的Flexbox语法(从2011年开始)到Opera和Chrome支持的最新规范。更糟糕的是,Firefox和其他WebKit浏览器(如Safari)支持更老版本的语法(从2009年开始)。最重要的是,Modernizr报告IE10支持现代Flexbox,即使它不支持,因此我们需要像这样处理IE10,而不是Modernizr规则。有关详细信息和说明,请参阅下面的Flexbox智能后备部分。
我正在使 flow horizontal,但强制<nav>
使用以下规则固定在自己的行上:
nav {
padding: 1rem;
-webkit-flex: 1 100%;
-moz-flex: 1 100%;
-ms-flex: 1 100%;
flex: 1 100%;
}
设置flex-basis
为100%
使其占据其父级宽度的100%,从而强制其他Flexbox子级换行到新行。该<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%,或宽度的2/5,第二个<article>
(图像容器)跨越宽度的60%或3/5 。这是值得记住的 - 比例值只占item所在行上的空间的比例,而不是子级所在行的所有行。
注意:flex-basis
指定的值首先应用于Flexbox子元素; 之后,父级留下的空间根据flex-grow
比例值在子级之间划分。如果flex-grow
没有明确设置值,就像nav
上面的规则集一样,它默认为1.有关这些工作原理的更多信息,请阅读我的快速跟踪布局的必杀技?文章。
Child flexboxes
当你将一个元素设置为一个灵活的盒子时,它只会flex它的直接子节点而不是其他后代。但是没有什么可以阻止你使一些非常复杂的布局让那些后代变成灵活的盒子!在这里,我也设置了<nav>
一个Flexbox,所以我可以有效地集中它,而不必担心它有多宽:
nav {
display: -ms-flexbox;
-ms-box-orient: horizontal;
-ms-box-pack: center;
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
; 我也确<li>
的整个宽度width: 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的一个特殊值,它允许flex子项尊重min-width
类型值,并在没有多余空间时保持不变的大小,但是当有多余的空间可以用时,就会扩展它以填充多余空间。看看展开和收缩页面时会发生什么(如图2所示)?
图2:神奇的伸缩灵活菜单!
我也flex了第二个<article>
,并将其中的段落像这样排列(每个段落都包含一个图像):
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
值,因此随着宽度的增加和减少,它们将改变每行的数量(参见图3 - 再次,不需要媒体查询),并使item和item内容都在中间,水平和垂直。
图3:一个很好的响应式图像框,没有媒体查询
Flexbox的智能回退
对Flexbox的支持即将到来(WebKit浏览器,基于Presto的Opera,Firefox支持有限,很快就会出现在其他人中!)但是在支持真正成为主流之前还需要一段时间。这意味着,如果我们想在生产代码中使用Flexbox,我们现在需要使用一些智能替代方案。某些浏览器(旧的WebKits和Firefox)支持2009年的旧版Flexbox语法。从2011年开始,IE10支持奇怪的新旧混合。幸运的是,Modernizr功能检测库具有现代Flexbox语法和传统Flexbox语法的功能检测功能flexbox
,以及和flexbox-legacy
标志。但还有一个问题 - Modernizr的测试报告IE10支持现代Flexbox,而不是Flexbox遗留。它实际上也不支持 - 它支持中间语法!这就是为什么我们在主要CSS规则中将IE10特定属性放在我们的代码中,而不是在下面将看到的Modernizr代码块中处理它们。
注意:有关如何处理Modernizr Flexbox IE10检测问题的讨论,截至2013年4月仍在进行中。
下表提供了现代Flexbox语法的摘要,以及2009和2011混合语法中的等效语法:
最终语法 | 2009语法 | 2011混合语法 |
---|---|---|
display: flex | display: box | display: flexbox |
flex-direction: row | box-orient: horizontal | box-orient: horizontal |
justify-content: flex-start | box-pack: start | box-pack: start |
align-items: flex-start | box-align: start | box-align: start |
flex: 1 | box-flex: 1 | flex: 1 |
注意:box-lines
2009规范中有一个属性,看起来相当于flex-wrap
,但遗憾的是,任何支持旧语法的浏览器似乎都不支持这一属性。因此我的例子不起作用,所以我不得不为旧浏览器简化它。
所以我在我的示例中为不支持Flexbox的浏览器提供了以下后备样式,但是支持Flexbox遗留:
/* legacy Flexbox fallback */
.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的浏览器,我们已经有了以下内容:
.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创建的布局在不同的屏幕宽度本来就非常灵活。
首先,对传统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和没有flex的所有浏览器进行修复。
@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在支持legacyflex的浏览器中并不能真正有效地实现。按照标准,我的示例运行得不错,尽管传统布局不如现代的Flexbox布局好;另一个有趣的问题是,Firefox似乎拒绝将已经作为Flexbox布局的内容放在中心,使用的是“margin: 0 auto
”(在Safari中,居中效果很好)。
但是,对于简单的Flexbox使用,你可以在各种现代浏览器上运行良好:Chrome,Firefox,Safari,Opera Presto 12.1 +,IE 10 +,iOS和Android。