您的位置:首页 > 其它

深入了解 Flexbox 伸缩盒模型

2015-05-20 16:44 441 查看

概念和术语

虽然现在我们可以使用 Flexbox 轻松创建布局,而不会像以前那样难以理解,但我们仍然需要花一些时间去熟悉到底如何使用 Flexbox。新的术语和概念可能会是我们使用 Flexbox 时的一个障碍,所以让我们先来了解以下它们。

Flexbox 由 伸缩容器 和 伸缩项目 组成。通过设置元素的 display 属性为
flex
inline-flex
可以得到一个伸缩容器。设置为
flex
的容器被渲染为一个块级元素,而设置为
inline-flex
的容器则渲染为一个行内元素。

这里的示例创建了一个伸缩容器。

1 2 3 4.flex-container {
display: -webkit-flex;
display: flex;
}
本文中所有的示例都会带有相应的浏览器厂商前缀。

伸缩容器中的每一个子元素都是一个伸缩项目。伸缩项目可以是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说,Flexbox 定义了伸缩容器内伸缩项目该如何布局。

Flex Lines 伸缩行

伸缩项目沿着伸缩容器内的一个 伸缩行 定位。通常每个伸缩容器只有一个伸缩行。



这个示例展示了2个项目在默认情况下的定位:沿着一个水平伸缩行从左至右显示。

<div class="flex-container">
<div class="flex-item">flex item 1</div>
<div class="flex-item">flex item 2</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 100px;
margin: 5px;
}


Writing Modes 书写模式

在你设计 Flexbox 时的有一个重要的部分是更改伸缩行的方向。默认情况下,伸缩行和文本方向一致:从左至右,从上往下。

这是 W3C 关于一个名为书写模式的新特性工作草稿。书写模式是一个新的方法,让你可以从右往左写,甚至竖着写,就像你知道的某些语言一样。

书写模式是一个正在进行的计划,但是 Chrome 已经率先支持了
direction
CSS 属性。如果我们在上一个例子中设置方向为
rtl
(从右往左) 那么不仅仅文字会从右往左书写,而且 伸缩行也改变了方向,并更改了页面的布局。

<div class="flex-container">
<div class="flex-item">flex item 1</div>
<div class="flex-item">flex item 2</div>
</div>


body {
direction: rtl;
}

.flex-container { display: -webkit-flex; display: flex; width: 300px; height: 240px; background-color: Silver; } .flex-item { background-color: DeepSkyBlue; width: 100px; height: 100px; margin: 5px; }


这也许就是 Flexbox 为什么如此抽象难懂的地方。当你正在制作一个语言不确定的页面时你不能简单的只是说“上”、“下”、“左”、“右”。

The Main Axis and the Cross Axis 主轴和侧轴

为了描述抽象的书写模式,Flexbox 使用 主轴 和 侧轴的概念。伸缩行跟随主轴。侧轴则垂直于主轴。



起点、终点和各轴的方向的名称如下:

主轴起点 Main Start

主轴终点 Main End

主轴方向 Main Direction (有时候也成为伸缩流方向 Flow Direction)

侧轴起点 Cross Start

侧轴终点 Cross End

侧轴方向 Cross Direction

在继续了解之前明白主轴和侧轴是至关重要的。Flexbox 中的一切都和这些轴有关。在我们所有的例子中,书写模式都是从左至右,从上到下,但是你需要记住并不是所有的 Flexbox 都是这样的。

伸缩容器的属性

flex-direction 伸缩流的方向

flex-direction
允许你更改伸缩容器的主轴方向。
flex-direction
的默认值是
row
。该值表示伸缩项目根据
书写模式
的方向布局。再次提醒,默认是从左至右,从上到下。其他的值如下:

row-reverse: 主轴起点和主轴终点交换。如果书写模式是从左至右,伸缩项目则是从右往左显示。

column: 主轴和侧轴交换。如果书写系统是垂直的,那么伸缩项目也是垂直显示的。

column-reverse: 和 column 一样,但是方向相反。

让我们把前一个示例中的
flex-direction
改为
column


<div class="flex-container">
<div class="flex-item">flex item 1</div>
<div class="flex-item">flex item 2</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 100px;
margin: 5px;
}


现在我们的伸缩项目就是垂直显示的了。

justify-content 主轴对齐

伸缩容器的
justify-content
属性用于调整主轴上伸缩项目的位置。可能的值为:

flex-start (默认)

flex-end

center

space-between

space-around

这里我们设置
justify-content
center
让伸缩项目在主轴上居中对齐:

.flex-container {
display: -webkit-flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 100px;
margin: 5px;
}


flex-start
,
flex-end
, 和
center
一看就懂。
space-between
space-around
则是分配伸缩项目之间空白空间的不同方法。这张规范中的图示很好的解释了一切:



align-items 侧轴对齐

align-items
是一个和
justify-content
相呼应的属性。
align-items
调整伸缩项目在侧轴上的定位方式。可能的值有:

flex-start (默认)

flex-end

center

baseline

stretch

这里我们设置
align-items
center
让伸缩项目在侧轴上居中对齐:

.flex-container {
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 100px;
margin: 5px;
}


和之前一样,
flex-start
,
flex-end
, 和
center
的意义显而易见。
stretch
也很简单:它会将伸缩项目从侧轴起点拉伸到侧轴终点。
baseline
则是让伸缩项目与它们的基线对齐。基线根据伸缩项目的内容计算得到。下面这张来自W3C标准的图例很好的解释了这些属性:



flex-wrap 伸缩行换行

目前为止,每个伸缩容器都有且只有一个伸缩行。使用
flex-wrap
你可以为伸缩容器创建多个伸缩行。这个属性接受以下值:

nowrap (默认)

wrap

wrap-reverse

如果
flex-wrap
设置为
wrap
,在一个伸缩行容不下所有伸缩项目时,伸缩项目会换行到一条新增的伸缩行上。新增的伸缩行根据侧轴的方向添加。

我们使用
flex-wrap
来看个例子:

<div class="flex-container">
<div class="flex-item">flex item 1</div>
<div class="flex-item">flex item 2</div>
<div class="flex-item">flex item 3</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyblue;
width: 100px;
height: 70px;
margin: 5px;
}


wrap-reverse
和 wrap 一样,只是新的伸缩行会被添加到侧轴的反方向上。

align-content 堆栈伸缩行

align-content
会更改
flex-wrap
的行为。它和
align-items
相似,但是不是对齐伸缩项目,它对齐的是伸缩行。可能你已经想到了,它接受的值也很相似:

stretch (默认)

flex-start

flex-end

center

space-between

space-around

这些值与
justify-content
align-items
中的值一样。

在这个例子中,我们设置
align-content
center


<div class="flex-container">
<div class="flex-item">flex item 1</div>
<div class="flex-item">flex item 2</div>
<div class="flex-item">flex item 3</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-align-content: center;
align-content: center;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 70px;
margin: 5px;
}


flex-flow 伸缩方向与换行

flex-flow
flex-direction
flex-wrap
的缩写。


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


举个例子:

1 2 3 4.flex-container {
-webkit-flex-flow: column nowrap;
flex-flow: column nowrap;
}
view rawgistfile1.cssThis Gist brought to you by GitHub.

伸缩项目的属性

一个伸缩项目是一个伸缩容器的子元素。伸缩容器中的文本也被视为一个伸缩项目。

伸缩项目中内容与普通流一样。举例来说,当一个伸缩项目被设置为浮动,你依然可以在这个伸缩项目中放置一个浮动元素。

伸缩项目都有一个 主轴长度(Main Size) 和一个 侧轴长度(Cross Size)。主轴长度是伸缩项目在主轴上的尺寸。侧轴长度是伸缩项目在侧轴上的尺寸。或者说,一个伸缩项目的宽或高取决于伸缩容器的轴,可能就是它的主轴长度或侧轴长度。

下面的属性可以调整伸缩项目的行为:

order 显示顺序

order
是最简单明了的属性。设置伸缩项目的 order 可以调整它们渲染时的顺序。在这个例子中,我们设置其中一个伸缩项目的
order
为 -1,于是它被提前到了其他伸缩项目的最前面。

<div class="flex-container">
<div class="flex-item">flex item 1</div>
<div class="flex-item first">flex item 2</div>
<div class="flex-item">flex item 3</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-align-content: center;
align-content: center;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 100px;
margin: 5px;
}

.first {
-webkit-order: -1;
order: -1;
}


如果需要文档顺序和显示顺序不同时,这就是个很有用的功能了。

margin 外边距

你应该对
margin: auto;
这种用法很熟悉。在伸缩盒中,它也能做同样的事情,但是更加强大。一个 "auto" 的 margin 会合并剩余的空间。它可以用来把伸缩项目挤到其他位置。

这里我们在第一个伸缩项目上声明了
margin-right: auto;
,导致了所有的剩余空间被合并到那个元素的右边去了:

.flex-container {
display: -webkit-flex;
display: flex;
-webkit-align-content: center;
align-content: center;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 50px;
height: 50px;
margin: 5px;
}

.flex-item:first-child {
margin-right: auto;
}


这里我们使用
margin: auto;
来重现经典CSS布局中的圣杯:真·垂直居中:

<div class="flex-container">
<div class="flex-item">I'm centered!</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 100px;
height: 100px;
margin: auto;
}


align-self 侧轴对齐

伸缩项目的
align-self
属性会覆盖该项目的伸缩容器的
align-items
属性。它的值和
align-items
一样:

stretch (默认)

flex-start

flex-end

center

baseline

在这个例子中我们为每个伸缩项目应用了不同的
align-self
值:

<div class="flex-container">
<div class="flex-item item1">flex-start</div>
<div class="flex-item item2">flex-end</div>
<div class="flex-item item3">center</div>
<div class="flex-item item4">base</div>
<div class="flex-item item5">line</div>
<div class="flex-item item6">stretch</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
width: 44px;
min-height: 100px;
margin: 3px;
}

.item1 {
-webkit-align-self: flex-start;
align-self: flex-start;
}
.item2 {
-webkit-align-self: flex-end;
align-self: flex-end;
}

.item3 {
-webkit-align-self: center;
align-self: center;
}

.item4 {
-webkit-align-self: baseline;
align-self: baseline;
}

.item5 {
-webkit-align-self: baseline;
align-self: baseline;
padding: 2em 0;
}

.item6 {
-webkit-align-self: stretch;
align-self: stretch;
}


我在例子中包含了2个基线对齐的伸缩项目,因为它们的对齐需要互相作用。

flex 伸缩性

现在我们终于要开始设置伸缩盒的伸缩性了。
flex
指定了一个伸缩项目该如何分配主轴上的剩余空间。

让我们一次把所有的常见值都看一遍吧。

flex: [number]

这个语法指定了一个数字,代表了这个伸缩项目该占用的剩余空间比例。

在这个例子中,第一个伸缩项目占用了 2/4 的剩余空间,而另外两个各占用了 1/4 的剩余空间。

<div class="flex-container">
<div class="flex-item item1">flex: 2</div>
<div class="flex-item item2">flex: 1</div>
<div class="flex-item item3">flex: 1</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
margin: 5px;
}

.item1 {
-webkit-flex: 2;
flex: 2;
}

.item2 {
-webkit-flex: 1;
flex: 1;
}

.item3 {
-webkit-flex: 1;
flex: 1;
}


如果把每个伸缩项目都设置为 1 的话,那么剩余空间就会被平均分配了。

<div class="flex-container">
<div class="flex-item item1">flex: 1</div>
<div class="flex-item item2">flex: 1</div>
<div class="flex-item item3">flex: 1</div>
</div>


.flex-container {
display: -webkit-flex;
display: flex;
width: 300px;
height: 240px;
background-color: Silver;
}

.flex-item {
background-color: DeepSkyBlue;
margin: 5px;
-webkit-flex: 1;
flex: 1;
}


flex: initial

一个
flex
属性值被设为
initial
的伸缩项目,在有剩余空间的情况下不会有任何变化,但是在必要的情况下会被收缩。

flex: auto

一个
flex
属性值被设为
auto
的伸缩项目,会根据主轴自动伸缩以占用所有剩余空间。

auto
目前仅在 Opera 12.11 尚有效,在 Chrome 23.0.1271.95 上无效。你可以通过使用
flex: 1;
来达到一样的效果。

flex: none

一个
flex
属性值被设为
none
的伸缩项目,在任何情况都不会发生伸缩。

flex 缩写

flex
也可以把
flex-grow
,
flex-shrink
, 和
flex-basis
这3个缩写为1个声明:


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


大多数情况下没必要使用这种语法。另外,它需要一个更容易理解的伸缩算法。如果你觉得自己挺厉害的,到规范里看一下吧

当然你也可以将
flex-grow
,
flex-shrink
, 和
flex-basis
作为单个属性分开来设置。但我强烈反对这种方式:当使用
flex
缩写时,即使没有某些值没有设置也能获得更合理的默认值。

visibility 叠加项目

当该值生效时,应用
visibility: collapse;
visibility: hidden;
display: none;
的效果是不一样的。如果是
collapse
,该元素会影响伸缩容器的侧轴长度,但不会被现实或占用主轴的空间。如果你想动态添加或移除伸缩项目又不会影响伸缩容器的侧轴长度,这将会非常有用。

目前为止,
visibility: collapse;
还没有被让任何浏览器正确的实现。现在
visibility: collapse;
还和
visibility: hidden;
实现着一样的效果。我希望能尽快得到改观。

你可以在 这里 看到
collapse
应该是如何工作的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: