掌握 Flex 项目的换行

Flexbox 被设计为一个一维布局工具——它处理将项目作为行或列进行布局——但不能同时进行这两者。但是,可以将弹性项目换行到新行,如果flex-directionrow,则创建新行,如果 flex-directioncolumn,则创建新列。本指南解释了 Flexbox 换行,它的设计用途以及哪些情况需要CSS 网格布局 而不是 Flexbox。

使项目换行

flex-wrap 属性的初始值为 nowrap。这意味着,如果一组弹性项目太宽而无法容纳在它们的弹性容器中,它们将溢出容器。要使它们在太宽时换行,请添加 flex-wrap 属性并将其值设置为 wrap,或者使用简写形式flex-flow,并将其值设置为 row wrapcolumn wrap。然后,项目在溢出其容器时将换行到新行。

在此示例中,有十个弹性项目,其 flex-basis160px,可以增长和缩小。一旦没有足够的空间在一行中放置另一个 160 像素的项目,就会创建一条新的弹性线。根据需要创建新行,直到放置所有项目为止。由于项目可以增长,因此它们将扩展以完全填充每一行。如果最后一行只有一个项目,它将拉伸以填充整行。

Flex 列也会发生同样的情况。要换行并创建新列,容器需要具有高度。在列的情况下,项目垂直拉伸以完全填充每一列。

换行和 flex-direction

当与 flex-direction 结合使用时,换行会按预期工作。如果 flex-direction 设置为 row-reverse,则项目将从容器的末端边缘开始,并以反向排序的行进行布局。

请注意,反转仅发生在内联行方向上。我们从右侧开始,然后转到第二行,然后再次从右侧开始。我们不会在两个方向上反转,从底部开始向上到容器!

单维布局说明

正如我们从上面的示例中看到的,如果允许我们的项目增长和缩小,当最后一行或列中的项目较少时,这些项目会增长以填充可用空间。

Flexbox 没有提供任何特性来让一行中的项目与上一行中的项目对齐——每条弹性线都像一个新的弹性容器。它处理主轴上的空间分配。如果只有一个项目,并且允许该项目增长,它将填充轴,就像您只有一个项目的弹性容器一样。如果您想要二维布局,那么您可能需要使用网格布局。

此示例演示了差异,使用 CSS 网格布局创建具有尽可能多的至少为 160px 的列的布局,并在所有列之间分配额外的空间。我们使用与上面弹性盒换行行示例相同的 HTML,但在其上设置 display: grid。我们没有使用 flex 简写(在弹性盒之外无效),而是使用 grid-template-columns 直接在容器上设置项目的最小宽度和增长能力。使用 CSS 网格,最后一个项目保留在其网格单元格中;当最后一行的项目较少时,网格项目不会拉伸。

这是在一维和二维布局之间的区别。在一维布局方法(如 Flexbox)中,我们只控制行或列。在二维网格布局中,我们同时控制两者。如果希望逐行分配空间,请使用 Flexbox。如果不希望,请使用 CSS 网格。

基于 Flexbox 的网格系统如何工作?

基于 Flexbox 的布局可以强制对齐为网格系统,但这并非 Flexbox 的预期用途。如果您为弹性项目分配百分比宽度——无论是使用 flex-basis 还是通过向项目本身添加宽度并将 flex-basis 的值保留为 auto——您可以给人以二维布局的印象。

在此示例中,flex-growflex-shrink 已设置为 0 以创建不可变形的弹性项目。灵活性通过百分比控制。

此技术允许您在交叉轴上对齐弹性项目。但是,当您发现自己以这种方式向弹性项目添加宽度或添加空弹性项目以占用空间时,这表明您可能希望切换到 CSS 网格布局来处理该组件。

在项目之间创建间距

要创建弹性项目之间的间隙或填充,请直接在弹性容器上使用 gap 属性来创建相邻弹性项目之间的固定空间。gap 属性是 row-gapcolumn-gap 的简写。这些属性指定网格、弹性盒和多列布局中行和列之间填充的大小。

gap 属性不是唯一可以增加项目之间空间的属性。边距、填充、justify-contentalign-content 也可以增加填充的大小,从而影响间隙的实际大小。

要查看 gap 属性在两个轴上与 margin 的区别,请尝试更改容器 .box 中的 gap 值,并在下面的样式表中向 .box > * 规则添加 margin 值。单击“重置”按钮以恢复到以前的值。

折叠的项目

Flexbox 规范详细说明了如果通过在项目上设置 visibility: collapse 来折叠弹性项目时会发生什么。请参阅 MDN 文档中有关 visibility 属性的说明。规范将行为描述如下

"在弹性项目上指定 visibility:collapse 会导致它成为一个折叠的弹性项目,产生的效果类似于在表格行或表格列上使用 visibility:collapse:折叠的弹性项目完全从渲染中移除,但会留下一个“撑杆”,以保持弹性线的交叉尺寸稳定。因此,如果弹性容器只有一条弹性线,则动态折叠或展开项目可能会更改弹性容器的主尺寸,但保证不会影响其交叉尺寸,并且不会导致页面其余布局“抖动”。但是,在折叠后会重新进行弹性线换行,因此具有多条线的弹性容器的交叉尺寸可能会或可能不会更改。" - 折叠的项目

如果您希望例如使用 JavaScript 针对弹性项目显示和隐藏内容,则此行为非常有用。规范中的示例演示了一种这样的模式。

在以下实时示例中,我有一个未换行的弹性容器。第三个项目的内容比其他项目多,但设置为 visibility: collapse;因此,弹性容器保留了显示此项目所需高度的撑杆。如果从 CSS 中删除 visibility: collapse 或将值更改为 visible,您将看到项目出现,并且空间在未折叠的项目之间重新分配;弹性容器的高度不应改变。

注意:请使用 Firefox 查看以下两个示例,因为 Chrome 和 Safari 将折叠视为隐藏。

但是,当处理多行弹性容器时,您需要了解换行是在折叠后重新完成的。因此,浏览器需要重新执行换行行为以考虑折叠项目在内联方向上留下的新空间。

这意味着项目可能最终会出现在与开始时不同的行上。如果项目显示和隐藏,它很可能导致项目最终出现在不同的行中。

我在下一个实时示例中创建了此行为。您可以看到拉伸如何根据折叠项目的所在位置更改行。如果向第二个项目添加更多内容,则当它足够长时,它会更改行。然后,该顶行仅变得与一行文本一样高。

如果这导致您的布局出现问题,则可能需要重新考虑结构,例如将每一行放入单独的弹性容器中,以便它们不会发生行偏移。

使用 visibility: hiddendisplay: none

在之前的实时示例中,尝试使用 visibility: hiddendisplay: none 而不是 visiblity: collapse。使用 visibility: hidden,项目将变得不可见,但框将保留在格式化结构中,因此它仍然表现得好像它是布局的一部分。当您使用 display: none 时,项目将完全从格式化结构中移除。它不仅不可见,而且结构也被移除。这意味着计数器会忽略它,并且过渡等操作不会执行。