flexbox 的基本概念
弹性盒子布局模块(通常简称为 flexbox)是一种一维布局模型,用于在项目之间分配空间,并包含多种对齐功能。本文概述了 flexbox 的主要功能,我们将在本指南的其余部分中更详细地探讨这些功能。
当我们描述 flexbox 是一维时,我们指的是 flexbox 一次只处理一个维度的布局——要么是行,要么是列。这与 CSS Grid Layout 的二维模型形成对比,后者同时控制行和列。
Flexbox 的两个轴
使用 flexbox 时,你需要考虑两个轴——*主轴*和*侧轴*。主轴由 flex-direction 属性定义,侧轴垂直于主轴运行。我们使用 flexbox 所做的一切都与这些轴相关,因此从一开始就了解它们的工作原理是值得的。
主轴
主轴由 flex-direction 定义,它有四个可能的值
rowrow-reversecolumncolumn-reverse
如果你选择 row 或 row-reverse,你的主轴将沿行方向在**行内方向**上运行。
选择 column 或 column-reverse,你的主轴将沿**块方向**运行,从页面的顶部到底部。
侧轴
侧轴垂直于主轴。因此,如果你的 flex-direction(主轴)设置为 row 或 row-reverse,则侧轴沿列向下运行。
如果你的主轴是 column 或 column-reverse,那么侧轴沿行运行。
起始线和结束线
另一个重要的理解领域是 flexbox 不对文档的书写模式做任何假设。Flexbox 不仅仅假设所有文本行都从文档的左上角开始,然后向右侧运行,新行一个接一个地出现。相反,它支持所有书写模式,就像其他逻辑属性和值一样。
你可以在后面的文章中阅读更多关于 flexbox 和书写模式之间关系的信息;但是,以下描述应该有助于解释为什么我们不谈论左和右以及上和下,而是描述我们的弹性项目流动的方向。
如果 flex-direction 是 row,并且我正在使用英语,那么主轴的起始边将在左侧,结束边将在右侧。
如果我使用阿拉伯语,那么我的主轴的起始边将在右侧,结束边将在左侧。
在这两种情况下,侧轴的起始边都在弹性容器的顶部,结束边都在底部,因为这两种语言都具有水平书写模式。
过了一段时间,思考起始和结束而不是左和右会变得很自然,并且当你处理其他遵循相同模式的布局方法(例如 CSS Grid Layout)时,这将对你很有用。
弹性容器
使用 flexbox 进行布局的文档区域称为**弹性容器**。要创建弹性容器,请将其display属性设置为flex。当我们这样做时,该容器的直接子元素将成为**弹性项目**。你可以使用inline flex或inline-flex用于行内弹性容器,或使用block flex或flex用于块级弹性容器,显式控制容器本身是以行内还是块级格式化上下文显示。
初始值
与 CSS 中的所有属性一样,定义了一些初始值,因此新弹性容器的内容将按以下方式运行
- 项目以行显示(
flex-direction属性的默认值为row)。 - 项目从主轴的起始边缘开始。
- 项目在主维度上不拉伸但可以收缩(弹性项目的
flex-grow属性的默认值为0,其flex-shrink属性的默认值为1)。 - 项目将拉伸以填充侧轴的大小(
align-items属性的默认值为stretch)。 - 弹性项目的
flex-basis属性的默认值为auto。这意味着,在每种情况下,它都将等于水平书写模式下的弹性项目width,以及垂直书写模式下的弹性项目height。如果相应的width/height也设置为auto,则改用flex-basis的content值。 - 所有项目都将在一行中(
flex-wrap属性的默认值为nowrap),如果它们的组合width/height超过了包含元素的width/height,它们将溢出其容器。
结果是你的项目都会排成一排,以内容的大小作为它们在主轴上的大小。如果项目数量超出容器所能容纳的范围,它们将不会换行,而是会溢出。如果有些项目比其他项目高,所有项目都将沿着侧轴的整个长度拉伸。
你可以在下面的实时示例中看到它的样子。点击“播放”在 MDN Playground 中打开示例,并编辑项目或添加新项目以尝试 flexbox 的初始行为
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three <br />has <br />extra <br />text</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
}
.box {
border: 2px dotted rgb(96 139 168);
display: flex;
}
改变 flex-direction
向弹性容器添加 flex-direction 属性可以让我们改变弹性项目的显示方向。设置 flex-direction: row-reverse 将使项目沿行显示,但起始线和结束线会交换。
如果我们将 flex-direction 更改为 column,主轴将切换,我们的项目现在以列的形式显示。设置为 column-reverse,起始线和结束线将再次交换。
下面的实时示例将 flex-direction 设置为 row-reverse。尝试其他值——row、column 和 column-reverse——看看内容会发生什么。
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
}
.box {
border: 2px dotted rgb(96 139 168);
display: flex;
flex-direction: row-reverse;
}
使用 flex-wrap 的多行弹性容器
虽然 flexbox 是一维模型,但可以使 flex 项目在多行中换行。如果你这样做,你应该将每行视为一个新的 flex 容器。任何空间分布都将发生在每行中,而与前一行或后续行无关。
要实现换行行为,请添加属性 flex-wrap,并将其值设为 wrap。现在,如果你的项目太大而无法全部显示在一行中,它们将换到另一行。下面的实时示例包含已设置 width 的项目。项目的总宽度对于弹性容器来说太宽了。由于 flex-wrap 设置为 wrap,项目将在多行中换行。如果将其设置为 nowrap(这是初始值),它们将收缩以适应容器。它们之所以收缩,是因为它们使用了初始的 flexbox 值,包括 flex-shrink: 1,这允许项目收缩。如果项目无法收缩,或者无法收缩到足以适应的程度,使用 nowrap 将导致溢出。
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
width: 200px;
}
.box {
width: 500px;
border: 2px dotted rgb(96 139 168);
display: flex;
flex-wrap: wrap;
}
在指南 掌握弹性项目的换行 中了解更多关于换行弹性项目的信息。
flex-flow 简写
你可以将 flex-direction 和 flex-wrap 这两个属性组合成 flex-flow 简写。
在下面的实时示例中,尝试将第一个值更改为 flex-direction 的允许值之一——row、row-reverse、column 或 column-reverse,同时将第二个值更改为 wrap 和 nowrap。
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
width: 200px;
}
.box {
width: 500px;
border: 2px dotted rgb(96 139 168);
display: flex;
flex-flow: row wrap;
}
应用于弹性项目的属性
为了控制每个弹性项目的行内大小,我们直接通过三个属性来控制它们
我们将在下面简要介绍这些属性,但如果你想获取更全面的信息,请查看控制主轴上弹性项目的比例指南。
在我们理解这些属性之前,我们需要考虑**可用空间**的概念。当我们改变这些弹性属性的值时,我们正在改变可用空间在项目之间的分布方式。当我们要对齐项目时,可用空间的概念也很重要。
如果一个容器宽 500 像素,里面有三个宽 100 像素的项目,那么我们布局项目所需的空间就是 300 像素。这样就剩下 200 像素的可用空间。如果我们不改变初始值,那么 flexbox 会将这些空间放在最后一个项目之后。
如果我们希望项目增长并填充空间,那么我们需要一种方法来在项目之间分配剩余空间。我们应用于项目本身的 flex 属性,可以决定这些可用空间应该如何分配给兄弟弹性项目。
flex-basis 属性
flex-basis 定义了该项目的大小,就其作为可用空间留下的空间而言。此属性的初始值为 auto — 在这种情况下,浏览器会查看项目是否具有大小。在上面的示例中,所有项目的宽度都是 100 像素。这被用作 flex-basis。
如果项目没有大小,则使用内容的大小作为 flex-basis。这就是为什么当我们仅在父元素上声明 display: flex 来创建弹性项目时,所有项目都排成一行,并且只占用显示其内容所需的空间。
flex-grow 属性
当 flex-grow 属性设置为正整数时,如果有可用空间,弹性项目可以沿主轴从其 flex-basis 增长。项目是否拉伸以占据该轴上的所有可用空间,或者仅仅是可用空间的一部分,取决于其他项目是否也允许增长以及它们的 flex-grow 属性的值。
每个具有正值的项目都会根据其 flex-grow 值占用一部分可用空间。如果我们将上面示例中的所有项目都赋予 flex-grow 值为 1,那么弹性容器中的可用空间将平均分配给我们的项目,并且它们将沿主轴拉伸以填充容器。如果我们将第一个项目赋予 flex-grow 值为 2,而其他项目各赋予 1,则总共有 4 份;第一项将获得可用空间的 2 份(在上面的示例中,200px 中的 100px),其余两项各获得 1 份(200px 中的 50px)。
flex-shrink 属性
flex-grow 属性处理在主轴上增加空间,而 flex-shrink 属性则控制如何减小空间。如果容器中没有足够的空间来布局我们的项目,并且 flex-shrink 设置为正整数,那么项目可以变得比 flex-basis 小。与 flex-grow 一样,可以分配不同的值以使一个项目比其他项目收缩得更快——设置了更高 flex-shrink 值的项目将比具有较低值的兄弟项目收缩得更快。
项目可以收缩到其 min-content 大小。在计算实际收缩量时会考虑这个最小大小,这意味着 flex-shrink 在行为上可能看起来不如 flex-grow 一致。因此,我们将在文章 控制主轴上项目的比例 中更详细地研究此算法的工作原理。
注意:flex-grow 和 flex-shrink 的这些值是比例。通常,如果我们所有项目都设置为 flex: 1 1 200px,然后希望其中一个项目以两倍的速度增长,我们会将该项目设置为 flex: 2 1 200px。但是,如果你愿意,也可以使用 flex: 10 1 200px 和 flex: 20 1 200px。
flex 属性的简写值
你很少会看到 flex-grow、flex-shrink 和 flex-basis 属性单独使用;相反,它们被组合成 flex 简写。flex 简写允许你按此顺序设置这三个值——flex-grow、flex-shrink、flex-basis。
下面的实时示例允许你测试 flex 简写的不同值;请记住,第一个值是 flex-grow。将其设置为正值意味着项目可以增长。第二个是 flex-shrink — 设为正值时,项目可以收缩,但前提是它们的总值溢出主轴。最后一个值是 flex-basis;这是项目作为其增长和收缩的基础值。
<div class="box">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
}
.box {
border: 2px dotted rgb(96 139 168);
display: flex;
}
.one {
flex: 1 1 auto;
}
.two {
flex: 1 1 auto;
}
.three {
flex: 1 1 auto;
}
还有一些预定义的简写值涵盖了大多数用例。你经常会在教程中看到这些,并且在许多情况下,这些就是你所需要使用的全部。预定义值如下
flex: initialflex: autoflex: noneflex: <positive-number>
initial 值是一个CSS 全局关键字,表示属性的初始值。设置 flex: initial 会将项目重置为三个长手属性的初始值,这与 flex: 0 1 auto 相同。flex-grow 的初始值为 0,因此项目不会超过其 flex-basis 大小。flex-shrink 的初始值为 1,因此项目在需要时可以收缩,而不是溢出。flex-basis 的初始值为 auto。项目将使用在主维度上设置的任何大小,或者它们将从内容大小获取其大小。
使用 flex: auto 与使用 flex: 1 1 auto 相同;这类似于 flex: initial,只是项目在需要时可以增长并填充容器以及收缩。
使用 flex: none 将创建完全不可伸缩的弹性项目。它就像你写了 flex: 0 0 auto。项目不能增长或收缩,并将使用 flex-basis 为 auto 的 flexbox 进行布局。
你在教程中经常看到的简写是 flex: 1 或 flex: 2 等等。这与分别编写 flex: 1 1 0 或 flex: 2 1 0 等等是相同的。由于 flex-basis: 0,项目获得最小尺寸,然后按比例增长以填充可用空间。在这种情况下,flex-shrink 值 1 是多余的,因为项目从最小尺寸开始——它们没有被赋予任何可能导致它们溢出弹性容器的尺寸。
在下面的实时示例中尝试这些简写值。
<div class="box">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
}
.box {
border: 2px dotted rgb(96 139 168);
display: flex;
}
.one {
flex: 1;
}
.two {
flex: 1;
}
.three {
flex: 1;
}
项目之间的对齐、对齐和自由空间分布
Flexbox 的一个关键特性是能够在主轴和侧轴上对齐和对齐项目,以及在弹性项目之间分配空间。请注意,这些属性设置在弹性容器上,而不是项目本身上。
align-items
align-items 属性在侧轴上对齐所有弹性项目。
此属性的初始值为 stretch,这就是为什么弹性项目默认情况下会拉伸到弹性容器的高度(如果 flex-direction 设置为 column 或 column-reverse,则为宽度)。此高度可能来自容器中最高的项目,或在弹性容器本身上设置的大小。
你可以选择将 align-items 设置为 flex-start,或简单地设置为 start,以便使项目对齐到弹性容器的起始位置;设置为 flex-end,或简单地设置为 end,以便对齐到结束位置;或者设置为 center 以便对齐到中心。在实时示例中尝试一下——我已经为弹性容器设置了高度,以便你可以看到项目如何在容器内移动。看看将 align-items 的值设置为以下值时会发生什么
stretchflex-startflex-endstartendcenterbaselinelast baseline
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three <br />has <br />extra <br />text</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
}
.box {
width: 500px;
height: 130px;
border: 2px dotted rgb(96 139 168);
display: flex;
align-items: flex-start;
}
align-items 设置在弹性容器上,并影响所有弹性项目。如果你想以不同于其他项目的方式对齐某个弹性项目,你可以在该弹性项目上设置 align-self。
justify-content
justify-content 属性用于在主轴上对齐项目,即 flex-direction 设置的流向。初始值为 flex-start,它会将项目对齐到容器的起始边缘,但你也可以将值设置为 flex-end 以对齐到末尾,或者设置为 center 以对齐到中心。
你还可以使用 space-between 值,它会在项目布局后将所有剩余空间均匀地分配给项目,从而使每个项目之间都有相等的空间。要使每个项目左右(或列的上下)都有相等的空间,请使用 space-around 值。使用 space-around,项目两端都有半个空间的间距。或者,要使项目周围有相等的空间,请使用 space-evenly 值。使用 space-evenly,项目两端都有一个完整空间的间距。
在实时示例中尝试以下 justify-content 值
startendleftrightnormalflex-startflex-endcenterspace-aroundspace-betweenspace-evenlystretch
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
}
.box {
border: 2px dotted rgb(96 139 168);
display: flex;
justify-content: flex-start;
}
文章 在弹性容器中对齐项目 更深入地探讨了这些属性,以便更好地理解它们的工作原理。然而,这些基本示例在大多数用例中都很有用。
justify-items
在弹性盒布局中,justify-items 属性被忽略。
place-items 和 place-content
place-items 属性是 align-items 和 justify-items 的简写属性。如果设置在弹性容器上,它将设置对齐方式而非对齐理由,因为 justify-items 在 flexbox 中被忽略。
还有另一个简写属性,place-content,它定义了 align-content 和 justify-content 属性。align-content 属性只影响换行的弹性容器,并在在弹性容器中对齐项目中讨论。
后续步骤
阅读本文后,你应对 flexbox 的基本功能有所了解。在下一篇文章中,我们将探讨 此规范如何与其他 CSS 部分相关联。