弹性方框模型 (Flexible Box Model) 快速入门

HTML5 Rocks

简介

我可以肯定,您对于页面上水平或垂直排列的样式元素已经了解得够多了。但是, CSS 还缺少适用于此任务的合适机制。了解 CSS3 弹性方框模型(简称 Flexbox

草案将 Flexbox 描述如下:

[...]针对接口设计而优化的 CSS 框模型。除了 CSS 中已有的布局系统之外,该模型还提供了一个额外的布局系统。[CSS21] 在这个新的框模型中,框的子代采用水平或垂直布局,而且可将未使用的空间分配给特定的子代,或者通过“弹性”分配给应展开的子代,在各子代间进行分配。这些框的嵌套(水平嵌套在垂直中,或垂直嵌套在水平中)可用于在两个维度中构建布局。该模型是以 XUL 用户界面语言的模型为基础的,适用于多种基于 Mozilla 应用程序(例如 Firefox)的用户界面。

太棒了。对于您这样的开发人员,哦不对,是布局架构师™来说,这意味着什么呢?

  1. 浮动?说啥呢,我们可不需要浮动。
  2. 以前具有挑战性的布局是更直观的。
  3. 我们可以创建真正具有弹性的布局,而浏览器将替我们完成计算工作。

Flexbox 为 display 属性赋予了一个新的值(即 box 值),还为我们提供了 8 个新的属性:

  • box-orient
  • box-pack
  • box-align
  • box-flex
  • box-flex-group
  • box-ordinal-group
  • box-direction
  • box-lines
8 个新属性啊?没错,是不是觉得太多了?那好,我们来分别介绍一下。

常用 Flexbox 样式属性

用于框的样式

display: box
该显示样式的新值可将此元素及其直系子代加入弹性框模型中。Flexbox 模型只适用于直系子代。
box-orient
值:horizontal | vertical | inherit
框的子代是如何排列的?还有两个值:inline-axis(真正的默认值)和 block-axis,但是它们分别映射到水平和垂直方向。
box-pack
值:start | end | center | justify
设置沿 box-orient 轴的框排列方式。因此,如果 box-orient 是水平方向,就会选择框的子代的水平排列方式,反之亦然。
box-align
值:start | end | center | baseline | stretch
基本上而言是 box-pack 的同级属性。设置框的子代在框中的排列方式。如果方向是水平的,该属性就会决定垂直排列,反之亦然。

用于框的子代的样式

box-flex
值:0 | 任意整数
该子代的弹性比。弹性比为 1 的子代占据父代框的空间是弹性比为 2 的同级属性的两倍。其默认值为 0,也就是不具有弹性。

上面的 box-flex-groupbox-ordinal-groupbox-directionbox-lines 属性我就不介绍了,因为老实说,您的大部分 Flexbox 作品都未必会用到这些。如果您在使用中想了解这些属性,请访问摘要中的链接。

关于语法的说明:目前,要在 Webkit 和 Gecko 中实施 Flexbox,就必须使用供应商前缀。在本教程中,为了清晰起见,我略去了大部分此类内容。有关详情,请参阅浏览器支持部分。

什么是弹性?

box-flex 样式属性定义了 Flexbox 的子代是弹性还是非弹性的,并且有助于定义该子代相对其同级的弹性比。我们来演示一下这究竟是什么意思。首先,我们从 3 个框开始。
<div id="flexbox">
  <p>child 1</p>
  <p>child 2</p>
  <p>child 3</p>
</div>

现在,我们要将它们水平相邻排列,而且无论其中的内容如何都要始终保持同样的高度。目前您会怎样处理这个问题?大部分人可能不假思索地就浮动这些段落,也许向父代添加 overflow:hidden; 以便清除浮动定位。没什么特别的招数。但是利用 Flexbox,我们就能轻松实现同样的目的。

#flexbox { 
  display: box;
  box-orient: horizontal;
}

在上面的代码中,我们只需告知父代根据此 Flexbox 模型进行操作,并沿水平轴排列其所有子代。不用任何浮动。好耶!

子代的宽度仍保留指定值(或者在未指定的情况下保留其固有宽度)。这意味着如果所有子代的总宽度小于父代的总宽度,我们就会得到这样的效果:

3 个子代元素在父代元素中保留其固有宽度

默认情况下,Flexbox 的子代仍为非弹性。这可能看起来有点奇怪,但是这样就使得子代有机会加入弹性体验。但是如果您希望第一和第二个子代具有特定宽度,而第三个子代根据父代中的可用空间自行调整宽度,那要怎么做呢?这种情况下就轮到 Flexbox 大显身手了:

#flexbox { 
  display: box;
  box-orient: horizontal;
}
#flexbox > p:nth-child(3) {
  box-flex: 1;
}

我们将最后一个子代设为弹性的,以占据可用空间。由于我们只对一个元素分配了空间,它将占据所有可用空间。

第三个子代元素(具有弹性)占据可用空间。

请注意,该元素只有在框的轴向上是具有弹性的;在本例中,也就是在水平方向上具有弹性。

box-flex 的值是相对值。因此,如果我们将第二和第三个子代设为弹性的:

#flexbox { 
  display: box;
  box-orient: horizontal;
}
#flexbox > p:nth-child(2),
#flexbox > p:nth-child(3) {
  box-flex: 1;
}

它们将各占据同样大小的可用空间,实际上就是平分了可用空间。

3 个子代元素中的 2 个平分了父代元素中的可用空间。
现在,我们也可以将 3 个子代的 box-flex 分别设为 123,然后它们就会按照这样的比例吸收其父代的多余空间。让我们实际操作看看。

基本示例

查看下面的代码和结果:

悬停在某个框上,查看弹性框的实际效果:当悬停目标展开时,其余的框就会缩小,但是总宽度始终和父代框的大小保持一致。

此处采用的样式其实只有两种:display: box 将内容转为 Flexbox 模式,然后子代的 box-flex: 1 在弹性模式下运行这些内容,从而占据所有额外空间。默认方向为水平,因此 box-orient: horizontal 其实并不是必需的,但是为了表达清晰和便于维护,最好还是加上。默认的 box-align 是弹性的,因此这些 div 占据了其父代框的整个高度。还不错吧?您可以在拉斐尔·戈特 (Raphael Goetter) 制作的这一演示中了解此技术在导航中的应用。

让我们更深入一些。

中央舞台:居中定位

在 CSS 中,将对象在水平和垂直方向上的居中一直以来都是个挑战。在仅限 CSS 的前提下,我们能拿出的最佳解决方案就是 position:absolute; left: 50%; top: 50%; 与等于一半宽度/高度的负左侧/顶部边距相结合。而这只能搭配大小确定的元素。啊!

詹姆斯·约翰·马尔科姆 (James John Malcom) 写道,有一种方法可以根据至少有 6 年历史的 display:table-cell;(杜桑·亚诺夫斯基 (Dušan Janovský) 曾在 2004 年写过)来垂直对齐。詹姆斯在此记录了完整的水平和垂直解决方案。此方案甚至不需要大小确定的元素即可生效。

借助 Flexbox,我们可以更轻松地实现这一点:

我们并不在子代上设置 box-flex,因为我们不希望它使用额外空间。我们只希望它无论大小如何都居中。这样做的一大优势在于,我们无需知道明确的尺寸即可将其居中。通常,我们可以使用块或内联对象来完成此操作。就是这么好用。

浏览器支持

那么您现在就能在工作中使用弹性框模型吗?还不行,至少不是对所有浏览器都有效。目前,我们尚未在 IE9 或 Opera 10.60 中实现 Flexbox,但是它曾在 IE9 Platform 的某个预览中出现过,因此微软有可能在未来某个时间添加此功能。

Caniuse.com 列出了当前支持的浏览器,即 Firefox 3 及更高版本、Safari 3 及更高版本以及 Chrome 浏览器。如果您要开发的是移动 Webkit,那么 Flexbox 将是标准布局方案的绝佳替代品。

当然,所有这些仍处于实验阶段,因此您还是应该使用供应商前缀:

/* i wish it was as easy as this: */

display: box;
box-orient: horizontal; 
box-pack: center;
box-align: center;
  
/* but in reality you'll need to do this: */

display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;

display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack: center;
-moz-box-align: center;

display: box;
box-orient: horizontal;
box-pack: center;
box-align: center;
  

如果您觉得这牵涉到很多分类,艾利克斯·拉塞尔 (Alex Russell) 将所有这些选项归纳成了一些实用的帮助类别

摘要

即使不考虑其他 4 个属性,也已经存在了很多可能性。要进一步了解 Flexbox,请参阅 Isotoma 的 Flexbox 演示Mozilla Hacks 上关于 Flexbox 的帖子W3C Flexbox 规范。开始动手设计些布局吧。尽情体验吧!

部分教程基于斯蒂芬·哈伊编写的指南(他已同意根据 CC-by 授权其作品)。

Comments

0