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: wrapdisplay: flex 搭配使用以封装子项

Flex 子项显示为挤压,下面哪个 Flex 属性有助于缓解这种情况?

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

Flexbox 对齐概览

Flexbox 自带一组属性,可用于对齐项目和分配项目之间的空间。这些属性非常有用,它们已被纳入各自的规范,您在网格布局中也会遇到它们。您可以在此处了解在使用 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 容器时,您可能有空间在交叉轴上进行分布。在这种情况下,您可以使用与 justify-content 相同值的 align-content 属性。与默认将项与 flex-start 对齐的 justify-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-direction: row 的 Flex 项。最后一个项定义了 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 内容在主轴上作为一个组。 因此,没有从该组中拆分个别项的概念。

在网格布局中,justify-selfjustify-items 属性会在内嵌轴上运行,以便在网格区域内对该轴上的项进行对齐。由于 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 垂直对齐,请使用

对齐关键字
不错
两全其美
抱歉
.container {
  display: flex;
  direction: ltr;
}

如需使用 Flexbox 进行水平对齐,请使用

对齐关键字
抱歉
对关键字进行排版
不错
.container {
  display: flex;
  direction: ltr;
}

默认情况下,Flex 项会对齐到 stretch。如果要将内容大小用于子项,您会使用以下哪种样式?

justify-content: flex-start
justify 属性适用于水平对齐,而非垂直对齐。
align-content: start
content 用于对齐 flex 行,而不是对齐子项。
height: auto
这不会产生任何影响。
align-items: flex-start
是的,我们希望将其垂直对齐到“顶部”或起始位置,这会移除默认的拉伸值,改为使用内容高度。

资源