Flexbox

CSS 播客 - 第 10 集:Flexbox

在自适应设计中,边栏与某些内容内嵌在一起是一种比较棘手的设计模式。在视口空间充裕的情况下,这种模式非常适用,但在空间较为紧凑的情况下,这种刚性布局可能会出现问题。

柔性框布局模型 (flexbox) 是专为一维内容设计的布局模型。 它擅于获取大量不同大小的项,并为这些项返回最佳布局。

这是此边栏模式的理想布局模型。Flexbox 不仅有助于内嵌排列边栏和内容,而且当剩余空间不足时,边栏会另起一行。使用 Flexbox 时,您可以提供灵活的边界来提示内容的显示方式,而不是为浏览器设置严格的尺寸。

您可以使用 Flex 布局执行哪些操作?

Flex 布局具有以下特性,您可以在本指南中探索这些特性。

  • 它们可以显示为行或列。
  • 它们遵循文档的书写模式。
  • 它们默认是单行,但可以要求换行显示。
  • 布局中的项在视觉上可以重新排序,与它们在 DOM 中的顺序不同。
  • 空间可以分布在各项内容中,以便它们根据其父项中的可用空间变大或变小。
  • 您可以使用 Box Alignment 属性在换行布局中围绕内容和 Flex 行分配空间。
  • 内容本身可以在交叉轴上对齐。

主轴和交叉轴

了解 Flexbox 的关键在于了解主轴和交叉轴的概念。主轴是指由 flex-direction 属性设置的轴。如果该值为 row,则主轴沿行;如果该值为 column,则主轴沿列。

三个相邻的盒子,每个盒子都带有一个从左到右的箭头。箭头标示为“主轴”

Flex 内容会在主轴上作为一个群组移动。 请注意:我们有许多内容,并且正在尝试为它们找到最佳布局。

交叉轴沿与主轴相反的方向延伸,因此如果 flex-directionrow,交叉轴将沿着列延伸。

三个不同高度的框并排排列,中间有一个箭头,指向左到右。箭头标有“主轴”字样。还有一个箭头从上向下指向。此轴标签为“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 项子项的块级盒子。弹性项会立即开始使用其初始值来呈现一些 Flexbox 行为。

初始值的含义如下:

  • 各项内容会显示为一行。
  • 不换行。
  • 它们不会变大来填满容器。
  • 它们在容器的开头处对齐。

控制项的方向

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

  • row:项排列成行。
  • row-reverse: 项从 Flex 容器的末尾开始以行排列。
  • column:项以列的形式排列。
  • column-reverse:项从 Flex 容器的末尾开始以列的形式排列。

您可以在下面的演示中使用我们的一组项试用所有值。

反转项和无障碍功能的流程

使用任何会使视觉显示顺序与 HTML 文档中的顺序不一致的属性时,都应谨慎小心,因为这可能会对无障碍功能产生负面影响。row-reversecolumn-reverse 值就是一个很好的例子。重新排序仅适用于视觉顺序,而非逻辑顺序。请务必了解这一点,因为逻辑顺序是屏幕阅读器读出内容的顺序,也是使用键盘导航的用户遵循的顺序。

通过以下视频可以看出,在反向行布局中,当键盘导航遵循 DOM(而非视觉显示)时,链接之间的 Tab 键会断开连接。

任何可以更改 Flexbox 或网格中项顺序的操作都可能会导致此问题。因此,任何重新排序都应包括全面的测试,以确保您的网站不会使某些用户难以使用。

如需了解详情,请参阅以下内容:

书写模式和方向

Flex 内容默认以行排列。 行是按照写作模式和脚本方向流动的句子的方向排列的。这意味着,如果您使用的是从右到左 (rtl) 脚本方向的阿拉伯语,这些项将在右侧对齐。由于阿拉伯语句子的阅读方式是从右到左,因此 Tab 顺序也会从右侧开始。

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

因此,默认情况下,Flex 项的行为方式与文档的写入模式相关联。大多数教程都是使用英语或其他水平(从左到右)书写模式编写的。这样,我们就可以轻松假定 flex 项会在左侧对齐并水平排列。

结合主轴和横轴以及书写模式来考虑,我们在 Flexbox 中讨论 startend 而不是顶部、底部、左侧和右侧这一事实可能更易于理解。每个轴都有开始和结束。主轴的起点称为 main-start。因此,我们的 Flex 项目最初会从 main-start 排列。该轴的终点是 main-end。交叉轴的起点为 cross-start,终点为 cross-end

上述术语的带标签图

换行 flex 项

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

一个内含 9 个项的 Flex 容器已缩小,因此一个字词占一行,但由于空间不足以并排显示它们,因此这些 Flex 项延伸到了容器外面。
一旦达到最小内容大小,Flex 项就会开始溢出其容器

使用初始值显示的项会尽可能缩小,在溢出发生之前缩小到 min-content 大小。

如需使项封装,请向 flex 容器添加 flex-wrap: wrap

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

当 Flex 容器封装时,它会创建多个 Flex 行。在空间分配方面,每行都像一个新的 Flex 容器。因此,如果您换行,则无法让第 2 行的内容与第 1 行上方的内容对齐。这就是 flexbox 是一维的意思。 您可以控制一个轴(行或列)中的对齐方式,但不能同时控制这两个轴(就像在网格中一样)。

flex-flow 简写法

您可以使用缩写形式 flex-flow 设置 flex-directionflex-wrap 属性。例如,如需将 flex-direction 设置为 column 并允许内容换行,请使用以下代码:

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

控制 Flex 项内的空间

假设容器的空间比显示项所需的空间多,则项会从一开始就排列整齐,而不会扩大以填充空间。它们会在达到最大内容大小时停止增长。这是因为 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 意味着项最终会采用不同的大小,因为各个项之间共享的空间是在每个项以最大内容大小进行布局共享的。大型内容将会占据更多空间。 如需强制所有项的大小保持一致,并忽略内容的大小,请在演示中将 flex:auto 更改为 flex: 1

这会解压缩到:

  • flex-grow: 1:项可以超出其 flex-basis
  • flex-shrink: 1:项可以缩小到其 flex-basis 以下。
  • flex-basis: 0:项的基本大小为 0

使用 flex: 1 表示所有项的大小均为零,因此 Flex 容器中的所有空间都可以分配。由于所有项的 flex-grow 系数均为 1,因此它们都会均匀扩大,并且空间也会均等共享。

允许不同项以不同的速率成长

您不必为所有项都设置 1flex-grow 系数。您可以为 Flex 项指定不同的 flex-grow 系数。在下面的演示中,第一项具有 flex: 1、第二个 flex: 2 和第三个 flex: 3。随着这些项从 0 开始增长,Flex 容器中的可用空间会被分成 6 份。第一个项获得 1 份,第二个项获得 2 份,第三个项获得 3 份。

您可以通过 autoflex-basis 执行相同的操作,但您需要指定这三个值。第一个值为 flex-grow,第二个值为 flex-shrink,第三个值为 flex-basis

.item1 {
  flex: 1 1 auto;
}

.item2 {
  flex: 2 1 auto;
}

这是一种不太常见的用例,因为使用 autoflex-basis 是为了让浏览器能够确定空间分布。不过,如果您希望某个商品的展示次数比算法决定的略多一些,则该参数可能很有用。

重新排列 Flex 项

可以使用 order 属性对 Flex 容器中的项进行重新排序。此属性允许对序数组中的项进行排序。项会按 flex-direction 指定的方向排列,值越低越先排列。如果有多个项具有相同的值,则该值将与具有该值的其他项一起显示。

以下示例演示了这种排序。

检查您的理解情况

测试您对 Flexbox 的了解程度

默认 flex-direction

row
默认情况下,Flexbox 会将项放入一行中,并从起始位置对齐。开启封装功能后,系统会继续创建可供子项在其中流动的行。
column
将 flex-direction 设置为 column 是堆叠元素的好方法,但这不是默认值。

默认情况下,Flex 容器封装了子节点。

true
必须启用封装。
false
flex-wrap: wrap