aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/learn/css/css_layout/flexbox/index.html
blob: 22b14745c62634cdd304537ff5e91acb7a33ce35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
---
title: 弹性盒子
slug: Learn/CSS/CSS_layout/Flexbox
tags:
  - CSS
  - CSS 布局
  - Layouts
  - Learn
  - flexbox
  - 初学者
  - 弹性框
  - 教程
  - 文章
translation_of: Learn/CSS/CSS_layout/Flexbox
---
<div>{{LearnSidebar}}</div>

<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Practical_positioning_examples", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}</div>

<p class="summary">弹性盒子是一种用于按行或按列布局元素的一维布局方法 。元素可以膨胀以填充额外的空间, 收缩以适应更小的空间。 本文将解释所有的基本原理。</p>

<table class="learn-box standard-table">
 <tbody>
  <tr>
   <th scope="row">前提:</th>
   <td>HTML 基础 (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>),和了解CSS如何工作的(study <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Introduction to CSS</a>.)</td>
  </tr>
  <tr>
   <th scope="row">目标:</th>
   <td>学会如何使用弹性盒子布局系统来创建Web布局。</td>
  </tr>
 </tbody>
</table>

<h2 id="为什么是_弹性盒子">为什么是 弹性盒子?</h2>

<p>长久以来,CSS 布局中唯一可靠且跨浏览器兼容的创建工具只有 <a href="/zh-CN/docs/Learn/CSS/CSS_layout/Floats">floats</a> 和 <a href="/zh-CN/docs/Learn/CSS/CSS_layout/Positioning">positioning</a>。这两个工具大部分情况下都很好使,但是在某些方面它们具有一定的局限性,让人难以完成任务。</p>

<p>以下简单的布局需求是难以或不可能用这样的工具( <a href="/zh-CN/docs/Learn/CSS/CSS_layout/Floats">floats</a> 和 <a href="/zh-CN/docs/Learn/CSS/CSS_layout/Positioning">positioning</a>)方便且灵活的实现的:</p>

<ul>
 <li>在父内容里面垂直居中一个块内容。</li>
 <li>使容器的所有子项占用等量的可用宽度/高度,而不管有多少宽度/高度可用。</li>
 <li>使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同。</li>
</ul>

<p>正如你将在后面的章节中看到的一样,弹性盒子使得很多布局任务变得更加容易。让我们继续吧!</p>

<h2 id="一个简单的例子">一个简单的例子</h2>

<p>在本文中,我们将通过一系列练习来帮助你了解 弹性盒子的工作原理。开始前,您应该拷贝 mozila github 仓库的 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox0.html">弹性盒子0.html</a>  到本地  。在现代浏览器里打开它(比如 Firefox、Chrome),然后打开你的编辑器看一眼它的代码。你可以看它的<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox0.html">线上</a>实例。</p>

<p>你可以看到这个页面有一个含有顶级标题的 {{htmlelement("header")}} 元素,和一个包含三个 {{htmlelement("article")}} 的 {{htmlelement("section")}} 元素。我们将使用这些来创建一个非常的标准三列布局,如下所示:</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13406/flexbox-example1.png" style="border-style: solid; border-width: 1px; display: block; height: 324px; margin: 0px auto; width: 800px;"></p>

<h2 id="指定元素的布局为_flexible">指定元素的布局为 flexible</h2>

<p>首先,我们需要选择将哪些元素将设置为柔性的盒子。我们需要给这些 flexible 元素的父元素 {{cssxref("display")}} 设置一个特定值。在本例中,我们想要设置 {{htmlelement("article")}} 元素,因此我们给 {{htmlelement("section")}}(变成了 flex 容器)设置 display:</p>

<pre class="brush: css">section {
  display:flex
}</pre>

<p>结果如下:</p>

<p><br>
 <img alt="" src="https://mdn.mozillademos.org/files/13408/flexbox-example2.png" style="border-style: solid; border-width: 1px; display: block; height: 348px; margin: 0px auto; width: 800px;"></p>

<p>所以,就这样一个简单的声明就给了我们所需要的一切—非常不可思议,对吧? 我们的多列布局具有大小相等的列,并且列的高度都是一样。 这是因为这样的 flex 项(flex容器的子项)的默认值是可以解决这些的常见问题的。 后面还有更多内容。</p>

<div class="note">
<p><span style="font-size: 14px;"><strong>注意:</strong>假如你想设置行内元素为 flexible box,也可以置</span> {{cssxref("display")}} 属性的值为 <code>inline-flex。</code></p>
</div>

<h2 id="flex_模型说明">flex 模型说明</h2>

<p>当元素表现为 flex 框时,它们沿着两个轴来布局:</p>

<p><img alt="flex_terms.png" class="default internal" src="/files/3739/flex_terms.png" style="display: block; margin: 0px auto;"></p>

<ul>
 <li><strong>主轴(main axis)</strong>是沿着 flex 元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为<strong> main start</strong><strong> main end</strong></li>
 <li><strong>交叉轴(cross axis)</strong>是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 <strong>cross start</strong><strong> cross end</strong></li>
 <li>设置了 <code>display: flex</code> 的父元素(在本例中是 {{htmlelement("section")}})被称之为 <strong>flex 容器(flex container)。</strong></li>
 <li>在 flex 容器中表现为柔性的盒子的元素被称之为 <strong>flex 项</strong><strong>flex item</strong>)(本例中是 {{htmlelement("article")}} 元素。</li>
</ul>

<p>了解这些术语以便你阅读后续章节。 如果您对使用的任何术语感到困惑,您可以随时返回这里。</p>

<h2 id="列还是行">列还是行?</h2>

<p>弹性盒子提供了 {{cssxref("flex-direction")}} 这样一个属性,它可以指定主轴的方向(弹性盒子子类放置的地方)— 它默认值是 <code>row</code>,这使得它们在按你浏览器的默认语言方向排成一排(在英语/中文浏览器中是从左到右)。</p>

<p>尝试将以下声明添加到 section 元素的 css 规则里:</p>

<pre class="brush: css">flex-direction: column;</pre>

<p>你会看到,这会将那些元素设置为列布局,就像我们添加这些 CSS 之前。在继续之前,请从示例中删除此规则。</p>

<div class="note">
<p><strong>注意:</strong>你还可以使用 <code>row-reverse </code><code>column-reverse </code>值反向排列 flex 项目。用这些值试试看吧!</p>
</div>

<h2 id="换行">换行</h2>

<p>当你在布局中使用定宽或者定高的时候,可能会出现问题即处于容器中的 弹性盒子子元素会溢出,破坏了布局。你可以看一下 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox-wrap0.html">弹性盒子-wrap0.html</a> 示例(你也可以拷贝到本地),如下所示:</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13410/flexbox-example3.png" style="display: block; height: 646px; margin: 0px auto; width: 800px;"></p>

<p>在这里我们看到,子代确实超出了它们的容器。 解决此问题的一种方法是将以下声明添加到 section css 规则中:</p>

<pre class="brush: css">flex-wrap: wrap</pre>

<p>同时,把以下规则也添加到{{htmlelement("article")}} 规则中:</p>

<pre class="brush: css">flex: 200px;</pre>

<p>现在尝试一下吧;你会看到布局比原来好多了:</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13412/flexbox-example4.png" style="display: block; height: 646px; margin: 0px auto; width: 800px;">现在我们有了多行 弹性盒子— 任何溢出的元素将被移到下一行。在 article 元素上设置的 flex: 200px 规则,意味着每个元素的宽度至少是200px;我们将在后面更详细地讨论这个属性。你可能还注意到,最后一行上的最后几个项每个都变得更宽,以便把整个行填满。</p>

<p>但是这里我们可以做得更多。首先,改变 {{cssxref("flex-direction")}} 属性值为 <code>row-reverse</code> — 你会看到仍然有多行布局,但是每一行元素排列的方向和原来是相反的了。</p>

<h2 id="flex-flow_缩写">flex-flow 缩写</h2>

<p>到这里,应当注意到存在着 {{cssxref("flex-direction")}}{{cssxref("flex-wrap")}} — 的缩写 {{cssxref("flex-flow")}}。比如,你可以将</p>

<pre class="brush: css">flex-direction: row;
flex-wrap: wrap;</pre>

<p>替换为</p>

<pre class="brush: css">flex-flow: row wrap;</pre>

<h2 id="flex_项的动态尺寸">flex 项的动态尺寸</h2>

<p>现在让我们回到第一个例子,看看是如何控制 flex 项占用空间的比例的。打开你本地的 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox0.html">弹性盒子0.html</a>,或者拷贝 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox1.html">弹性盒子1.html</a> 作为新的开始(<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox1.html">查看线上</a>)。</p>

<p>第一步,将以下规则添加到 CSS 的底部:</p>

<pre class="brush: css">article {
  flex: 1;
}</pre>

<p>这是一个无单位的比例值,表示每个 flex 项沿主轴的可用空间大小。本例中,我们设置 {{htmlelement("article")}} 元素的 flex 值为 1,这表示每个元素占用空间都是相等的,占用的空间是在设置 padding 和 margin 之后剩余的空间。因为它是一个比例,这意味着将每个 flex 项的设置为 400000 的效果和 1 的时候是完全一样的。</p>

<p>现在在上一个规则下添加:</p>

<pre class="brush: css">article:nth-of-type(3) {
  flex: 2;
}</pre>

<p>现在当你刷新,你会看到第三个 {{htmlelement("article")}} 元素占用了两倍的可用宽度和剩下的一样 — 现在总共有四个比例单位可用。 前两个 flex 项各有一个,因此它们占用每个可用空间的1/4。 第三个有两个单位,所以它占用2/4或这说是1/2的可用空间。</p>

<p>您还可以指定 flex 的最小值。 尝试修改现有的 article 规则:</p>

<pre class="brush: css">article {
  flex: 1 200px;
}

article:nth-of-type(3) {
  flex: 2 200px;
}</pre>

<p>这表示“每个flex 项将首先给出200px的可用空间,然后,剩余的可用空间将根据分配的比例共享“。 尝试刷新,你会看到分配空间的差别。</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13406/flexbox-example1.png" style="border-style: solid; border-width: 1px; display: block; height: 324px; margin: 0px auto; width: 800px;"></p>

<p>弹性盒子的真正价值可以体现在它的灵活性/响应性,如果你调整浏览器窗口的大小,或者增加一个 {{htmlelement("article")}} 元素,这时的布局仍旧是好的。</p>

<h2 id="flex_缩写与全写">flex: 缩写与全写</h2>

<p>{{cssxref("flex")}} 是一个可以指定最多三个不同值的缩写属性:</p>

<ul>
 <li>第一个就是上面所讨论过的无单位比例。可以单独指定全写 {{cssxref("flex-grow")}} 属性的值。</li>
 <li>第二个无单位比例 — {{cssxref("flex-shrink")}} — 一般用于溢出容器的 flex 项。这指定了从每个 flex 项中取出多少溢出量,以阻止它们溢出它们的容器。 这是一个相当高级的弹性盒子功能,我们不会在本文中进一步说明。</li>
 <li>第三个是上面讨论的最小值。可以单独指定全写 {{cssxref("flex-basis")}} 属性的值。</li>
</ul>

<p>我们建议不要使用全写属性,除非你真的需要(比如要去覆盖之前写的)。使用全写会多写很多的代码,它们也可能有点让人困惑。</p>

<h2 id="水平和垂直对齐">水平和垂直对齐</h2>

<p>还可以使用 弹性盒子的功能让 flex 项沿主轴或交叉轴对齐。让我们一起看一下新例子 — <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flex-align0.html">flex-align0.html</a><a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flex-align0.html">在线浏览</a>)— 我们将会有一个整洁,灵活的按钮/工具栏。 此时,你看到了一个水平菜单栏,其中一些按钮卡在左上角,就像下面这样:</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13414/flexbox-example5.png" style="display: block; height: 77px; margin: 0px auto; width: 600px;"></p>

<p>首先,拷贝一份到本地。</p>

<p>然后,将下面的 CSS 添加到例子的底部:</p>

<pre class="brush: css">div {
  display: flex;
  align-items: center;
  justify-content: space-around;
}</pre>

<p>刷新一下页面,你就会看到这些按钮很好的垂直水平居中了。我们是通过下面所说的两个新的属性做到的。</p>

<p>{{cssxref("align-items")}} 控制 flex 项在交叉轴上的位置。</p>

<ul>
 <li>默认的值是 <code>stretch</code>,其会使所有 flex 项沿着交叉轴的方向拉伸以填充父容器。如果父容器在交叉轴方向上没有固定宽度(即高度),则所有 flex 项将变得与最长的 flex 项一样长(即高度保持一致)。我们的第一个例子在默认情况下得到相等的高度的列的原因。</li>
 <li>在上面规则中我们使用的 <code>center</code> 值会使这些项保持其原有的高度,但是会在交叉轴居中。这就是那些按钮垂直居中的原因。</li>
 <li>你也可以设置诸如 <code>flex-start</code><code>flex-end</code> 这样使 flex 项在交叉轴的开始或结束处对齐所有的值。查看 {{cssxref("align-items")}} 了解更多。</li>
</ul>

<p>你可以用 {{cssxref("align-self")}} 属性覆盖 {{cssxref("align-items")}} 的行为。比如,你可以这样:</p>

<pre class="brush: css">button:first-child {
  align-self: flex-end;
}</pre>

<p>去看看它产生的效果,然后删除它。</p>

<p>{{cssxref("justify-content")}} 控制 flex 项在主轴上的位置。</p>

<ul>
 <li>默认值是 <code>flex-start</code>,这会使所有 flex 项都位于主轴的开始处。</li>
 <li>你也可以用 <code>flex-end</code> 来让 flex 项到结尾处。</li>
 <li><code>center</code><code>justify-content</code> 里也是可用的,可以让 flex 项在主轴居中。</li>
 <li>而我们上面用到的值 <code>space-around</code> 是很有用的——它会使所有 flex 项沿着主轴均匀地分布,在任意一端都会留有一点空间。</li>
 <li>还有一个值是 <code>space-between</code>,它和 <code>space-around</code> 非常相似,只是它不会在两端留下任何空间。</li>
</ul>

<p>在继续下面之前,多多使用提到过的属性吧,看看它们的效果。</p>

<h2 id="flex_项排序">flex 项排序</h2>

<p>弹性盒子也有可以改变 flex 项的布局位置的功能,而不会影响到源顺序(即 dom 树里元素的顺序)。这也是传统布局方式很难做到的一点。</p>

<p>代码也很简单,将下面的 CSS 添加到示例代码下面。</p>

<pre class="brush: css">button:first-child {
  order: 1;
}</pre>

<p>刷新下,然后你会看到 "Smile" 按钮移动到了主轴的末尾。下面我们谈下它实现的一些细节:</p>

<ul>
 <li>所有 flex 项默认的 {{cssxref("order")}} 值是 0。</li>
 <li>order 值大的 flex 项比 order 值小的在显示顺序中更靠后。</li>
 <li>相同 order 值的 flex 项按源顺序显示。所以假如你有四个元素,其 order 值分别是2,1,1和0,那么它们的显示顺序就分别是第四,第二,第三,和第一。</li>
 <li>第三个元素显示在第二个后面是因为它们的 order 值一样,且第三个元素在源顺序中排在第二个后面。</li>
</ul>

<p>你也可以给 order 设置负值使它们比值为 0 的元素排得更前面。比如,你可以设置 "Blush" 按钮排在主轴的最前面:</p>

<pre class="brush: css">button:last-child {
  order: -1;
}</pre>

<h2 id="flex_嵌套">flex 嵌套</h2>

<p>弹性盒子也能创建一些颇为复杂的布局。设置一个元素为flex项目,那么他同样成为一个 flex 容器,它的孩子(直接子节点)也表现为 flexible box 。看一下 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/complex-flexbox.html">complex-弹性盒子.html</a><a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/complex-flexbox.html">在线浏览</a>)。</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13418/flexbox-example7.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>

<p>这个例子的 HTML 是相当简单的。我们用一个 {{htmlelement("section")}} 元素包含了三个 {{htmlelement("article")}}元素。第三个 {{htmlelement("article")}} 元素包含了三个 {{htmlelement("div")}}</p>

<pre>section - article
          article
          article - div - button
                    div   button
                    div   button
                          button
                          button</pre>

<p>现在让我们看一下布局用到的代码。</p>

<p>首先,我们设置 {{htmlelement("section")}} 的子节点布局为 flexible box。</p>

<pre class="brush: css">section {
  display: flex;
}</pre>

<p>下面我们给 {{htmlelement("article")}} 元素设置 flex 值。特别注意这里的第二条CSS规则—我们设置第三个 {{htmlelement("article")}} 元素的子节点的布局同样为 flex ,但是属性值为列布局。</p>

<pre class="brush: css">article {
  flex: 1 200px;
}

article:nth-of-type(3) {
  flex: 3 200px;
  display: flex;
  flex-flow: column;
}
</pre>

<p>接下来,我们选择了第一个 {{htmlelement("div")}}。首先使用 <code>flex: 1 100px;</code> 简单的给它一个最小的高度 100px,然后设置它的子节点({{htmlelement("button")}} 元素)为 flex 项。在这里我们将它们放在一个包装行(wrap row)中,使它们居中对齐,就像我们在前面看到的单个按钮示例中做的那样。 </p>

<pre class="brush: css">article:nth-of-type(3) div:first-child {
  flex: 1 100px;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  justify-content: space-around;
}</pre>

<p>最后,我们给按钮设置大小,有意思的是我们给它一个值为1的 flex 属性。如果你调整浏览器窗口宽度,你会看到这是一个非常有趣的效果。按钮将尽可能占用最多的空间,尽可能多的堆在同一条线上,但是当它们不再适合在同一条线上,他们中的一些会到下一行去。</p>

<pre class="brush: css">button {
  flex: 1;
  margin: 5px;
  font-size: 18px;
  line-height: 1.5;
}</pre>

<h2 id="跨浏览器兼容性">跨浏览器兼容性</h2>

<p>大多数浏览器都支持 弹性盒子,诸如 Firefox, Chrome, Opera, Microsoft Edge 和 IE 11,较新版本的 Android/iOS 等等。但是你应该要意识到仍旧有被人使用的老浏览器不支持 弹性盒子(或者支持,但是只是支持非常非常老版本的 弹性盒子)。</p>

<p>虽然你只是在学习和实验,这不太要紧; 然而,如果您正在考虑在真实网站中使用弹性盒子,则需要进行测试,并确保在尽可能多的浏览器中您的用户体验仍然可以接受。</p>

<p>弹性盒子相较其他一些 CSS 特性可能更为棘手。 例如,如果浏览器缺少 CSS 阴影,则该网站可能仍然可用。 但是假如不支持 弹性盒子功能就会完全打破布局,使其不可用。</p>

<p>我们将在未来的模块中讨论克服棘手的跨浏览器支持问题的策略。</p>

<h2 id="测试你的技能">测试你的技能</h2>

<p>我们在文章里面覆盖了很多内容,但你是否能记住最重要的知识? 在你继续学习前,你可以进行<a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox_skills">测试</a>来验证你是否掌握了这些知识。</p>

<h2 id="总结">总结</h2>

<p>到这里,介绍弹性盒子的基础知识就结束了。 我们希望你体会到乐趣,并且玩的开心,能随着你的学习与你一起向前。 接下来,我们将看到CSS布局的另一个重要方面—网格系统。</p>

<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Practical_positioning_examples", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}</div>