深入浅出Flexbox

简书的Markdown貌似不支持插入iframe,所以文章里的JSFiddle示例都改做截图了,如果有需要可以点击下面的链接,到众成查看,英文版链接一并附上。
译者:kangflict(飞扬)
链接:http://www.zcfy.cc/article/966
原文:https://bocoup.com/weblog/dive-into-flexbox

简介

Flexbox 是 CSS3 中提出的新布局模型,用于适应现代网络开发中日益复杂的布局需求。 近来,Flexbox 的语法逐渐稳定下来,本文来为大家揭开它的神秘面纱,并盘点其技术细节。浏览器支持将会快速增长,因此当对 Flexbox 的支持足够广泛以至达到实用水平时,你将会在这场游戏当中拔得头筹。如果想要了解它的工作方式和原理,那么就继续读下去吧!

为什么需要 Flexbox?

长期以来,人们使用 table、float、inline-block 以及其他 CSS 特性来对站点内容进行布局。然而,这些工具没有一个是为当前的复杂网页或网络应用设计的。像垂直居中这样的简单的需求都需要费点儿力气才能满足,以至于我们通常认为单枪匹马实现灵活栅格布局这样的需求不太现实,因此各种 CSS 栅格布局框架获得了巨大的成功。

规范进展与浏览器支持

Flexbox 规范的相关工作已经进行 3 年之久,很多浏览器厂商都发布了其实验性质的实现。2012 年 9 月,针对 Flexbox 语法的第三次主要修订进入了 W3C 的候选推荐阶段。这说明 W3C 对当前的语法是满意的,并鼓励浏览器厂商进行实现。

Flexbox 规范大事年表:

  • 2009 年 7 月,工作草案(display: box;)
  • 2011 年 3 月,工作草案(display: flexbox;)
  • 2011 年 11 月,工作草案(display: flexbox;)
  • 2012 年 3 月,工作草案(display: flexbox;)
  • 2012 年 6 月,工作草案(display: flex;)
  • 2012 年 9 月,候选推荐(display: flexe;)

各个浏览器都在积极地接纳 Flexbox。本文写就之时,Chrome 22+、Opera 12.1+ 以及 Opera Mobile 12.1+ 均已支持 Flexbox。Firefox 18Blackberry 10 也将马上跟进。我建议使用支持 Flexbox 的浏览器来阅读本文,以便观察示例如何工作。

相关概念和术语

尽管在 Flexbox 的帮助下,以前千辛万苦才能实现或者根本不敢想象的布局都能轻而易举地实现,但要真正习惯以 Flexbox 的方式进行布局还是需要一定的时间。在使用 Flexbox 时,新的术语或概念都可能成为拦路虎,因此我们先来讨论一下术语和概念的问题。

Flexbox 布局涉及 Flex 容器(Flex Container)和 Flex 项目(Flex Item)。Flex 容器的 display 属性为 flexflexboxflex 属性使得容器渲染为块级元素,而 inline-flex 则使其渲染为行内元素。

下面是声明 Flex 容器的示例:

.flex-container {
  display: -webkit-flex;
  display: flex;
}

本文中的所有代码示例都将包含全面的浏览器厂商前缀。

Flex 容器的任何子元素都是 Flex 项目,并且 Flex 项目可以有任意多个。Flex 容器之外的任何元素以及 Flex 项目内的元素都将照常渲染。简而言之,Flex 容器决定 Flex 项目在其内部的布局方式。

Flex 布局线(Flex Line)

在Flex容器内,Flex 项目沿 Flex 布局线 排布。默认情况下,每个容器只有一条 Flex 布局线。

Flex 容器

上图的示例展示了默认情况下两个项目在容器中的排布:从左到右,沿水平 Flex 布局线排列。

Paste_Image.png

书写模式(Writing Modes)

使用 Flexbox 进行富有创造性的布局不可避免地要改变 Flex 布局线的方向。默认情况下,Flex 布局线与文本书写方向一致:从左到右,从上到下。

W3C 有一个工作草案,是关于一项称作书写模式(Writing Modes)的新特性的。书写模式为从右至左或纵向的文字排布提供了新的实现方式,在对特定的语言进行排版时常会遇到这样的需求。

书写模式仍然处于半成品状态,不过 direction 属性已经在 Chrome 中得到了支持。上面的示例中,如果如果我们将 direction 的值设置为 rtl (从右到左),那么不光文本内容会从右往左渲染,Flex 布局线的方向也会改变,从而影响页面的布局。

Paste_Image.png

这或许就是很多与 Flexbox 相关的术语非常抽象的原因。如果不能确定页面语言的话,我们就不能简单地用“上”“下”“左”“右”来代表布局方向。

主轴与侧轴(Main Axis and the Cross Axis)

Flexbox 通过引入概念主轴(Main Axis)和侧轴(Cross Axis)来体现对书写模式的支持。Flex 布局线与主轴的方向一致,而侧轴则与主轴正交。

主轴与侧轴

每条轴的起点、终点以及方向的名字如下所示:

  • 主轴起点(Main Start)
  • 主轴终点(Main End)
  • 主轴方向(Main Direction,有时也称作流方向,即 Flow Direction)
  • 侧轴起点(Cross Start)
  • 侧轴终点(Cross End)
  • 侧轴方向 (Cross Direction)

主轴和侧轴两个术语非常重要,我们有必要在继续之前将其彻底搞懂。在使用 Flexbox 进行布局的时候,任何东西都与此有关。本文所有的示例中,书写模式都是从左往右从上往下的,但是我们必须了解并不一定所有情况下都是如此。

Flex 容器之属性

flex-direction

flex-direction 能够改变 Flex 容器的轴向。flex-direction 的默认值为 row,即按照 writing-mode 的方向对 Flex 项目进行排布,默认情况下从左到右,从上往下。其他可能的值如下:

  • row-reverse:主轴起点和终点对换。如果书写模式(writing-mode)从左往右,那么此时 Flex 项目会由右往左进行排布;
  • column:主轴与侧轴对换。如果书写系统为水平方向的,那么 Flex 项目将沿纵向排布;
  • column-reverse:与column的效果相同,只是轴向翻转。

将前面示例中的 flex-direction 值改为 column

Paste_Image.png

现在,Flex 项目变为纵向排列的了。

justify-content

Flex 容器的 justify-content 属性用于控制 Flex 项目在主轴上的位置。可能的值有:

  • flex-start(默认值)
  • flex-end
  • center
  • space-between
  • space-around

justify-content 的值设置为 center 能够让 Flex 项目沿主轴居中:

Paste_Image.png

flex-startflex-end 以及 center 的含义相当直截,但是 space-betweenspace-around 这两个用于确定 Flex 项目间留白的属性值的含义就不那么明显了。下面这张来自规范的示意图对各个属性值做出了最佳诠释:

justify-content示例
justify-content示例

align-items

align-items 是对 justify-content 的补充,它确定的是 Flex 项目在侧轴上的位置。可能的取值有:

  • flex-start(默认值)
  • flex-end
  • center
  • baseline
  • stretch

我们将 align-items 的值设置为 center,从而让 Flex 项目在侧轴居中排布:

Paste_Image.png

flex-startflex-endcenter 的含义仍旧直截了当,strech 也相当简单:让 Flex 项目充满从侧轴起点到侧轴终点的所有空间。baseline 则使得 Flex 项目沿基线对齐。基线是由 Flex 项目的内容计算得出的。下面出自 Flexbox 规范的示意图对此做出了最佳阐释:

align-items示意图
align-items示意图

flex-wrap

到现在为止,每个 Flex 容器都只有一条 Flex 布局线,利用 flex-wrap 属性,就可以得到有多条 Flex 布局线的的容器。flex-wrap 可选的值如下:

  • nowrap(默认值)
  • wrap
  • wrap-reverse

如果 flex-wrap 的值为 wrap,那么当一条 Flex 布局线无法容纳所有 Flex 项目时,多余的项目就会折转到附加的 Flex 布局线上。新添的 Flex 布局线沿侧轴的方向排列。

这里有一个使用 flex-wrap 的示例:

Paste_Image.png

wrap-reverse 的效果与 wrap 相同,只是 Flex 布局线将沿与侧轴相反的方向添加。

align-content

align-content 能够影响 flex-wrap 的行为。它与 align-items 类似,但是并不是用于对齐 Flex 项目,而是用于对齐 Flex 布局线。正如你所想,它们可能的取值也非常相似:

  • stretch(默认值)
  • flex-start
  • flex-end
  • center
  • space-between
  • space-around

这些值的效果与它们在 align-items 中的表亲基本相同。

这里,我们将 align-content 设为 center

Paste_Image.png

flex-flow

flex-flowflex-directionflex-wrap 的简写:

flex-flow: [flex-direction] [flex-wrap]

例如:

gistfile1.css

.flex-container {
  -webkit-flex-flow: column nowrap;
  flex-flow: column nowrap;
}

Flex 项目之属性

Flex 项目是 Flex 容器的直接子元素,Flex 容器中的文字段落也会被当做 Flex 项目处理。

Flex 项目的内容则会照常渲染。例如,float 属性对 Flex 项目不起作用,但是 Flex 项目内部却可以存在浮动元素。

我们称 Flex 项目有主轴尺寸侧轴尺寸。主轴尺寸是 Flex 项目在主轴方向上的尺寸,侧轴尺寸则是 Flex 项目在侧轴方向上的尺寸。事实上,通常 Flex 项目的宽和高分别就是它的主轴尺寸和侧轴尺寸,不过这取决于 Flex 容器的轴的设置。

下面的属性能够影响 Flex 项目的行为。

order

order 最为简单,它控制着 Flex 项目的渲染顺序。本例中,我们将一个 Flex 项目的 order 属性设置为 -1,从而使其显示在所有其他元素之前。

Paste_Image.png

这对可访问性来说可能非常有用,因为有时我们需要文档结构和页面展示以不同的顺序出现。

margin

你或许已经对 margin: auto; 在通常情况下的效果非常熟悉了。在 Flexbox 的世界里,它仍然发挥着相似的作用,只不过更加的强大。“自动”边距能够吸收掉多余的空白,从而将 Flex 项目推到不同的位置上去。

这里,我们为第一个 Flex 项目设定 margin-right: auto;,从而使得该项目右边所有多余的空白都被吸收掉:

Paste_Image.png

接着,我们使用 margin: auto; 来摘取 CSS 排版的圣杯:真正的垂直居中!

Paste_Image.png

align-self

Flex 项目的 align-self 属性能够覆盖 Flex 容器为其指定的 align-items 属性。两个属性具有相同的取值范围:

  • stretch(默认)
  • flex-start
  • flex-end
  • center
  • baseline

此例中,我们为每个 Flex 项目指定了不同的 align-self 值:

Paste_Image.png

上例中有两个 Flex 项目的 align-items 值为 baseline,这是因为 baseline 项目是以彼此为参照来进行对齐的。

flex

终于到 Flexbox 中的 flex 属性了。flex 确定了 Flex 项目在主轴剩余空间排布时的策略。

让我们来逐一过目 flex 的常见取值:

flex: [数字]

该语法通过指定一个数字,来确定当前 Flex 项目占主轴剩余空间的比例。

本例中,第一个 Flex 项目占剩余空间的 2/4,其余两个 Flex 项目各占 1/4:

Paste_Image.png

将每个项目的 flex 属性都设置为 1 是一项非常有用的技巧,此时主轴剩余空间将被平均分配给各个 Flex 项目。

Paste_Image.png

flex: initial

flex 属性为 initial 的项目将会失去弹性伸缩能力,但是在必要的时候仍然能够缩小(被挤小)。

flex: auto

flex 属性为 auto 的项目拥有在主轴上进行弹性伸缩的所有能力。

目前,Opera 12.11 能够支持 auto,但是 Chrome 23.0.1271.95 还不可以。实际上,我们只需要使用 flex: 1 就可以绕过这个问题。

flex: none

flex 属性为 none 的项目在任何情况下都不具备弹性伸缩的能力。

flex 进阶

事实上,flexflex-growflex-shrinkflex-basis 的简写:

flex: [flex-grow] [flex-shrink] [flex-basis]

不过,多数情况下我们都不需要这样写,它需要对 flex 背后的算法更为精深的理解。如果你觉得自己是真正的猛士,看这里的规范

我们也可以为 flex-growflew-shrink 以及 flex-basis 分别指定属性值。但是我强烈建议你不要这样做,因为当使用 flex 简写形式时,浏览器会为没有值的属性指定更有意义的默认值。

visibility

如果有实现支持的话,对于 Flex 项目,visibility: collapse; 应当表现得与 visibility: hidden;display: none; 不同。具有该属性的 Flex 项目将会影响所在 Flex 容器的侧轴尺寸,但是并不占据主轴方向的空间,也不可见。这对动态添加移除 Flex 项目非常有用,同时也不影响 Flex 容器的侧轴尺寸。

目前,visibility: collapse; 貌似在任何浏览器上都没有得到正确的支持。当前的实现中,visibility: collapse; 的行为看上去与 visibility: hidden; 相同。我期待这种情况赶紧得以改观。

这里有一个还不错的 collapse 模拟实现,能够让你看到规范中 collapse 是如何工作的

总结

如你所见,Flexbox 是一种强大的新式布局工具,将从根本上变革我们现有的网站布局手段。亦如所见,它需要我们使用全新的思考方式来进行布局。我希望这篇文章能够在你开始使用 Flexbox 对网站进行布局时帮你一把。不知道你信不信,反正我是看到了光明的未来。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容