引言
CSS3 弹性布局模块 —— 短命名叫 Flexbox —— 为我们的 web 开发带来了许多能量和令人兴奋的畅想空间,我们可以快速轻松地搭建复杂的网站布局,摒弃一些我们惯常使用的不合理的 hacks 和 补丁。我的文章 《伸缩布局 — 打开布局天堂之门?》讲述了一些 Flexbox 的基础,本文将是进阶教程,我会带大家看一些高级点的例子,使用 Modernizr 为那些参差不齐的 flexbox 支持情况提供不同的样式,以便提供当前可用的最优的跨浏览器方案。
看下面例子
实例包含多层 flexbox 容器,比较急切的话可以先看看最终效果,然后继续探索代码细节。
总体布局
基本的网站布局像这样:
<section>
<nav></nav>
<article></article>
<article></article>
</section>
<section>
被设置成一个弹性盒子像这样:
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;
}
文档流是横向的,但是强制 <nav>
标签单独占一行,用以下定义:
nav {
padding: 1rem;
-webkit-flex: 1 100%;
-moz-flex: 1 100%;
-ms-flex: 1 100%;
flex: 1 100%; /*译者注:[ flex : 占父容器的比例 宽度基准值]*/
}
设置 flex-basis
(伸缩基准值)为100%,让 nav
导航占据它的父容器宽度的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。切记 —— 只有这些项在同一行时,这个比例值才有效。
flex-basis
(伸缩基准值),首先会应用到 flexbox 子元素,之后,父容器剩下的空间会根据
flex-grow
比例值分配。像上面的 nav 的样式,
flex-grow
没明确指定的话,默认会当成 1 。想学习更多的使用信息,可以读《
伸缩布局 — 打开布局天堂之门?》的“让你的元素可伸缩”那部分。
Child flexboxes(子元素弹性盒子)
当你把一个元素设置成弹性的盒子,仅有它的直接子元素可伸缩,更深层的后代元素不会起作用。但是没有什么可阻止你让这些后代元素也可伸缩,来吧,做一个真正复杂的布局!我已把 <nav>
设置成弹性布局,因此不必担心它有多宽,我会轻松地让它居中:
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
;
我也要确保 <a>
锚点占据 <li>
的整个宽度,设置为 width : 100%
。
接下来是见证奇迹的时刻,列表项看起来有点重叠,当它们折行的时候看起来很丑。无需 media queries (媒体查询)打造一个帅气的响应式菜单如何?仅需以下的 CSS 定义:
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
。auto
是 flex
很特别的值,它允许 flex 子元素根据已定义的 min-width
值平均分配可用空间,它会根据可用空间大小自动调节每个子元素的宽度。扩大和收缩此页面看看会发生什么(截图见图2)?
图2:神奇的响应式菜单!
我也把第二个 <article>
设置成弹性布局,像这样排列里面的 <p>
标签(每个包含一个图片):
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 —— 又一次无需 media queries),每一项内容都会保持水平居中,空间小时会垂直一列。
图3:无需 media queries 的响应式图片盒子。
flexbox 智能退化
这些浏览器支持 flexbox (WebKit 浏览器,基于 Presto 的 Opera,Firefox 支持有限,不久会完善!),在 flexbox 成为主流之前,支持它的浏览器还是比较少。显然,如果我们想用到生产环境代码中,需要一些智能的替代品。一些浏览器(老的 WebKit 们,Firefox)支持一些 2009年的老版的 flexbox 语法。IE 10 从2011年开始支持奇怪的新旧组合。万幸的是,Modernizr 特性检测框架可以帮助我们检测最新的 flexbox 语法和遗留的 flexbox 语法,它是通过 flexbox
和 flexbox-legacy
标记识别的。不过还有问题 —— Modernizr 反馈显示 IE 10 支持最新的 flexbox,实际还没支持 —— 它支持一种新旧之间的语法!这就是我们把 IE 10 专有的属性放到我们 CSS 代码里的原因。
下面的表格是关于最新的 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
属性,看起来像是
flex-wrap
的等价物,不幸的是支持老版语法的浏览器似乎不支持它。我怕例子无法正常运行,为老版浏览器做了简化。
因此我为不支持 flexbox 最新语法,但支持老版语法的浏览器写了退化样式:
/* 老版 flexbox 退化样式 */
.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;
}
为太宽和太窄的屏幕加一点简单的 media queries 代码
最后,我还是决定用一点 media queries ,仅仅是为了修复过窄的屏幕宽度问题。但是请自己斟酌用多小的尺寸: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 和不支持 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 queries 仅仅为了在很宽的屏幕上居中内容。
@media all and (min-width: 1100px) {
section {
width: 1100px;
margin: 0 auto;
}
}
结语
现在使用 flexbox 仍有一些限制,等主流浏览器都支持的时候就容易多了。如今,如果想保持简洁,保持一行用 flexbox 非常高效,在支持老 flexbox 语法的浏览器上,多行 flexbox 布局还不太好使。因为我的例子符合标准,所以它运行良好,尽管老版语法布局看起来没有最新 flexbox 语法布局那么帅;有个有意思的问题:用 flexbox 布局再用 margin : 0 auto 在 Firefox 貌似无法居中内容(在 Safari 运行良好)。
无论如何,对于简单的 flexbox 应用,在一大批主流浏览器上已经可以运行良好啦:Chrome, Firefox,Safari,Opera Presto 12.1+, IE 10+,iOS 和 Android。
原文地址:http://dev.oupeng.com/articles/advanced-cross-browser-flexbox