Flexbox

CSS 播客 - 010:Flexbox

在自适应设计中,一种可能比较棘手的设计模式是侧边栏与某些内容内联排列。在视口空间充足的情况下,这种模式效果很好,但当空间受到压缩时,这种僵化的布局可能会变得有问题。

弹性盒布局模型 (flexbox) 是一种为一维内容设计的布局模型。它擅长处理大量大小不同的项目,并返回这些项目的最佳布局。

这是此侧边栏模式的理想布局模型。Flexbox 不仅有助于内联布局侧边栏和内容,而且在剩余空间不足时,侧边栏会换行到新行。使用 flexbox,您可以提供灵活的边界来提示内容的显示方式,而不是为浏览器设置僵化的尺寸。

使用 flex 布局可以做什么?

Flex 布局具有以下功能,您将在本指南中进行探索。

  • 它们可以显示为行或列。
  • 它们尊重文档的书写模式。
  • 它们默认是单行的,但可以要求换行到多行。
  • 布局中的项目可以在视觉上重新排序,脱离它们在 DOM 中的顺序。
  • 空间可以分布在项目内部,因此它们会根据父容器中的可用空间而变大和变小。
  • 空间可以分布在换行布局中的项目和 flex 行周围,使用框对齐属性。
  • 项目本身可以在交叉轴上对齐。

主轴和交叉轴

理解 flexbox 的关键是理解主轴和交叉轴的概念。主轴是由您的 flex-direction 属性设置的轴。如果它是 row,则您的主轴沿行方向,如果它是 column,则您的主轴沿列方向。

Three boxes next to each other with an arrow, pointing left to right. The arrow is labelled Main axis

Flex 项目作为一个组在主轴上移动。请记住:我们有一堆东西,我们正在尝试为它们作为一个组获得最佳布局。

交叉轴在与主轴相反的方向上运行,因此如果 flex-directionrow,则交叉轴沿列方向运行。

Three boxes of different heights, next to each other with an arrow, pointing left to right. The arrow is labelled Main axis. There's another arrow pointing top to bottom. This one is labelled Cross axis

您可以在交叉轴上执行两项操作。您可以单独或作为一个组移动项目,以便它们相对于彼此和 flex 容器对齐。此外,如果您有换行的 flex 行,您可以将这些行视为一个组,以控制如何将空间分配给这些行。您将在本指南中看到这一切如何在实践中运作,现在只需记住主轴遵循您的 flex-direction 即可。

创建 flex 容器

让我们通过获取一组不同大小的项目并使用 flexbox 布局它们,来看看 flexbox 的行为方式。

<div class="container" id="container">
  <div>One</div>
  <div>Item two</div>
  <div>The item we will refer to as three</div>
</div>

要使用 flexbox,您需要声明您要使用 flex 格式化上下文,而不是常规的块和内联布局。为此,请将 display 属性的值更改为 flex

.container {
  display: flex;
}

正如您在布局指南中学到的那样,这将为您提供一个块级框,其中包含 flex 项目子项。flex 项目立即开始表现出一些 flexbox 行为,使用它们的初始值

初始值意味着

  • 项目显示为行。
  • 它们不换行。
  • 它们不会增长以填充容器。
  • 它们在容器的开头对齐。

控制项目的方向

即使您尚未添加 flex-direction 属性,项目也会显示为行,因为 flex-direction 的初始值为 row。如果您想要行,则无需添加该属性。要更改方向,请添加该属性以及以下四个值之一

  • row:项目按行布局。
  • row-reverse: 项目从 flex 容器的末尾开始按行布局。
  • column:项目按列布局。
  • column-reverse:项目从 flex 容器的末尾开始按列布局。

您可以使用以下演示中的项目组试用所有值。

反转项目流和可访问性

当使用任何将视觉显示重新排序为远离 HTML 文档中排序方式的属性时,您应该谨慎,因为它可能会对可访问性产生负面影响。row-reversecolumn-reverse 值就是这方面的一个很好的例子。重新排序仅发生在视觉顺序中,而不是逻辑顺序中。理解这一点很重要,因为逻辑顺序是屏幕阅读器将读出内容的顺序,并且任何人使用键盘导航都将遵循该顺序。

您可以在以下视频中看到,在反向行布局中,链接之间的选项卡切换如何变得断开连接,因为键盘导航遵循 DOM 而不是视觉显示。

任何可以更改 flexbox 或 grid 中项目顺序的东西都可能导致此问题。因此,任何重新排序都应包括彻底的测试,以检查它是否不会使某些人难以使用您的网站。

有关更多信息,请参阅

书写模式和方向

Flex 项目默认按行布局。行在句子在您的书写模式和脚本方向中流动的方向上运行。这意味着,如果您使用阿拉伯语(具有从右到左 (rtl) 的脚本方向),则项目将在右侧对齐。选项卡顺序也将从右侧开始,因为这是在阿拉伯语中阅读句子的方式。

如果您使用垂直书写模式(如某些日语字体),则行将垂直运行,从上到下。尝试更改此演示中的 flex-direction,该演示正在使用垂直书写模式。

因此,flex 项目的默认行为方式与文档的书写模式相关。大多数教程都是使用英语或其他水平、从左到右的书写模式编写的。这很容易让人认为 flex 项目在左侧对齐并水平运行。

考虑到主轴和交叉轴以及书写模式,我们在 flexbox 中谈论startend而不是顶部、底部、左侧和右侧可能更容易理解。每个轴都有一个起点和一个终点。主轴的起点称为 main-start。因此,我们的 flex 项目最初从 main-start 对齐。该轴的终点是 main-end。交叉轴的起点是 cross-start,终点是 cross-end

A labelled diagram of the above terms

换行 flex 项目

flex-wrap 属性的初始值为 nowrap。这意味着,如果容器中没有足够的空间,项目将溢出。

A flex container with nine items inside it, the items have shrunk down so one word is on a line
but there is not enough room to show them side by side so the flex items have extended outside the
box of the container.
一旦达到 min-content 大小,flex 项目将开始溢出其容器

使用初始值显示的项目将尽可能缩小,直至 min-content 大小,然后才会发生溢出。

要使项目换行,请将 flex-wrap: wrap 添加到 flex 容器。

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

当 flex 容器换行时,它会创建多个 flex 行。在空间分布方面,每行都像一个新的 flex 容器。因此,如果您正在换行,则无法使第 2 行中的内容与第 1 行中上方的某些内容对齐。这就是 flexbox 是一维的含义。您可以控制一个轴(行或列)中的对齐方式,而不是像我们在 grid 中那样同时控制两个轴。

flex-flow 简写

您可以使用简写 flex-flow 设置 flex-directionflex-wrap 属性。例如,要将 flex-direction 设置为 column 并允许项目换行

.container {
  display: flex;
  flex-flow: column wrap;
}

控制 flex 项目内部的空间

假设我们的容器具有比显示项目所需的更多空间,则项目在开头对齐,并且不会增长以填充空间。它们在 max-content 大小时停止增长。这是因为 flex- 属性的初始值为

  • flex-grow: 0:项目不增长。
  • flex-shrink: 1:项目可以缩小到小于它们的 flex-basis
  • flex-basis: auto:项目的基础大小为 auto

这可以用 flex: initial 的关键字值表示。flex 简写属性或 flex-growflex-shrinkflex-basis 的长手属性应用于 flex 容器的子项。

要使项目增长,同时允许大项目比小项目具有更多空间,请使用 flex:auto。您可以使用上面的演示尝试此操作。这将属性设置为

  • flex-grow: 1:项目可以增长到大于它们的 flex-basis
  • flex-shrink: 1:项目可以缩小到小于它们的 flex-basis
  • flex-basis: auto:项目的基础大小为 auto

使用 flex: auto 将意味着项目最终会具有不同的大小,因为在每个项目都按 max-content 大小布局后,在项目之间共享的空间才会被共享出去。因此,较大的项目将获得更多空间。要强制所有项目的大小一致并忽略内容的大小,请在演示中将 flex:auto 更改为 flex: 1

这会展开为

  • flex-grow: 1:项目可以增长到大于它们的 flex-basis
  • flex-shrink: 1:项目可以缩小到小于它们的 flex-basis
  • flex-basis: 0:项目的基础大小为 0

使用 flex: 1 表示所有项目的大小都为零,因此 flex 容器中的所有空间都可用于分配。由于所有项目的 flex-grow 因子都为 1,因此它们都会均匀增长,并且空间会均匀共享。

允许项目以不同的速率增长

您不必为所有项目提供 flex-grow 因子 1。您可以为您的 flex 项目提供不同的 flex-grow 因子。在下面的演示中,第一个项目具有 flex: 1,第二个项目具有 flex: 2,第三个项目具有 flex: 3。由于这些项目从 0 增长,因此 flex 容器中的可用空间被分为六份。一份给第一个项目,两份给第二个项目,三份给第三个项目。

您可以从 flex-basisauto 的情况执行相同的操作,尽管您需要指定三个值。第一个值是 flex-grow,第二个值是 flex-shrink,第三个值是 flex-basis

.item1 {
  flex: 1 1 auto;
}

.item2 {
  flex: 2 1 auto;
}

这是一种不太常见的用例,因为使用 flex-basisauto 的原因是允许浏览器计算空间分布。但是,如果您想让项目比算法决定的增长得更多一点,这可能会很有用。

重新排序 flex 项目

可以使用 order 属性重新排序 flex 容器中的项目。此属性允许对序数组中的项目进行排序。项目按照 flex-direction 指示的方向布局,值最低的项目在前。如果多个项目具有相同的值,则它将与具有该值的其他项目一起显示。

以下示例演示了此排序。

检查您的理解情况

测试您对 flexbox 的知识

默认的 flex-direction

row
默认情况下,flexbox 会将项目放入一行中,并将它们在开头对齐。启用换行后,它将继续为子项创建行以在其中流动。
column
将 flex-direction 设置为 column 是堆叠元素的好方法,但它不是默认值。

默认情况下,flex 容器会包装子项。

true
必须启用换行。
false
flex-wrap: wrapdisplay: flex 一起使用以包装子项

Flex 子项目看起来被挤压了,哪个 flex 属性有助于缓解这种情况?

flex-grow
此属性描述元素是否可以超出基础大小增长,而不是描述元素在基础大小下的行为方式。
flex-shrink
是的,此属性描述了当宽度低于基础大小时如何处理尺寸调整。
flex-basis
这提供了尺寸调整的起点,但没有提供如何在宽度低于基础大小时(例如在挤压场景中)处理尺寸调整方案。

Flexbox 对齐概述

Flexbox 带来了一组用于对齐项目和在项目之间分配空间的属性。这些属性非常有用,因此后来已被移至它们自己的规范中,您也将在 Grid Layout 中遇到它们。在这里,您可以了解它们在使用 flexbox 时的工作方式。

这组属性可以分为两组。用于空间分布的属性和用于对齐的属性。用于分布空间的属性是

  • justify-content:主轴上的空间分布。
  • align-content:交叉轴上的空间分布。
  • place-content:用于设置上述两个属性的简写形式。

在 flexbox 中用于对齐的属性

  • align-self:在交叉轴上对齐单个项目。
  • align-items:在交叉轴上对齐所有项目作为一个组。

如果您在主轴上工作,则属性以 justify- 开头。在交叉轴上,它们以 align- 开头。

在主轴上分布空间

使用之前使用的 HTML,flex 项目按行布局,主轴上有空间。这些项目不够大,无法完全填充 flex 容器。这些项目在 flex 容器的开头对齐,因为 justify-content 的初始值为 flex-start。项目在开头对齐,任何额外的空间都在末尾。

justify-content 属性添加到 flex 容器,为其提供值 flex-end,项目将在容器的末尾对齐,备用空间将放置在开头。

.container {
  display: flex;
  justify-content: flex-end;
}

您还可以使用 justify-content: space-between 在项目之间分布空间。

在演示中尝试一些值,并查看 MDN 以获取所有可能的值。

使用 flex-direction: column

如果您已将 flex-direction 更改为 column,则 justify-content 将在列上工作。要在作为列工作时在容器中具有备用空间,您需要为您的容器提供 heightblock-size。否则,您将没有备用空间可以分布。

尝试不同的值,这次使用 flexbox 列布局。

在 flex 行之间分布空间

使用换行的 flex 容器,您可能需要在交叉轴上分布空间。在这种情况下,您可以使用 align-content 属性,其值与 justify-content 相同。与默认情况下将项目对齐到 flex-startjustify-content 不同,align-content 的初始值为 stretch。将属性 align-content 添加到 flex 容器以更改该默认行为。

.container {
  align-content: center;
}

在演示中试用一下。该示例具有换行的 flex 项目行,并且容器具有 block-size,以便我们有一些备用空间。

place-content 简写

要同时设置 justify-contentalign-content,您可以使用 place-content,其中包含一个或两个值。单个值将用于两个轴,如果您指定两个值,则第一个值用于 align-content,第二个值用于 justify-content

.container {
  place-content: space-between;
  /* sets both to space-between */
}

.container {
  place-content: center flex-end;
  /* wrapped lines on the cross axis are centered,
  on the main axis items are aligned to the end of the flex container */
}

在交叉轴上对齐项目

在交叉轴上,您还可以使用 align-itemsalign-self 在 flex 行中对齐您的项目。此对齐方式的可用空间将取决于 flex 容器的高度,或者在换行项目集的情况下取决于 flex 行的高度。

align-self 的初始值为 stretch,这就是为什么默认情况下行中的 flex 项目会拉伸到最高项目的高度。要更改此设置,请将 align-self 属性添加到您的任何 flex 项目。

.container {
  display: flex;
}

.item1 {
  align-self: flex-start;
}

使用以下任何值来对齐项目

  • flex-start
  • flex-end
  • center
  • stretch
  • baseline

请参阅 MDN 上的完整值列表

下一个演示有一行 flex 项目,其中 flex-direction: row。最后一个项目定义了 flex 容器的高度。第一个项目具有 align-self 属性,其值为 flex-start。尝试更改该属性的值,以查看它如何在交叉轴上的空间内移动。

align-self 属性应用于单个项目。align-items 属性可以应用于 flex 容器,以将所有单个 align-self 属性设置为一个组。

.container {
  display: flex;
  align-items: flex-start;
}

在下一个演示中,尝试更改 align-items 的值,以将交叉轴上的所有项目作为一个组对齐。

为什么 flexbox 中没有 justify-self?

Flex 项目在主轴上作为一个组运行。因此,没有将单个项目从该组中分离出来的概念。

在 grid 布局中,justify-selfjustify-items 属性在内联轴上工作,以在该轴上对齐其 grid 区域内的项目。由于 flex 布局将项目视为一个组的方式,因此这些属性未在 flex 上下文中实现。

值得注意的是,flexbox 与自动边距配合得非常好。如果您遇到需要将一个项目从组中分离出来或将组分成两个组的情况,您可以应用边距来执行此操作。在下面的示例中,最后一个项目的左边距为 auto。自动边距会吸收其应用方向上的所有空间。这意味着它会将项目向右推,从而分割组。

如何垂直和水平居中项目

对齐属性可用于将项目居中放置在另一个框内。justify-content 属性在主轴(即行)上对齐项目。align-items 属性在交叉轴上对齐项目。

.container {
  width: 400px;
  height: 300px;
  display: flex;
  justify-content: center;
  align-items: center;
}

检查您的理解情况

测试您对 flexbox 的知识

.container {
  display: flex;
  direction: ltr;
}

要使用 flexbox 垂直对齐,请使用

align 关键字
不错
justify 关键字
抱歉
.container {
  display: flex;
  direction: ltr;
}

要使用 flexbox 水平对齐,请使用

align 关键字
抱歉
justify 关键字
不错
.container {
  display: flex;
  direction: ltr;
}

默认情况下,flex 项目与 stretch 对齐。如果您希望将内容大小用于子项目,您将使用以下哪种样式?

justify-content: flex-start
justify 属性用于水平对齐,而不是垂直对齐。
align-content: start
content 对齐 flex 行,而不是子项目对齐。
height: auto
这将不起作用。
align-items: flex-start
是的,我们希望将它们垂直对齐到“顶部”或开头,这将删除默认的 stretch 值,而是使用内容高度。

资源