需要反馈:我们应如何定义 CSS 砌体?

Ian Kilpatrick
Ian Kilpatrick
Tab Atkins-Bittner
Tab Atkins-Bittner

发布时间:2024 年 9 月 19 日;上次更新时间:2026 年 2 月 13 日

CSS 工作组已将这两个 CSS 砌体提案合并为一个规范草稿。该小组希望此举能让用户更轻松地比较这两款设备,并做出最终决定。Chrome 团队仍然认为,采用单独的 masonry 语法是最好的方式。虽然我们之前的帖子中提到的最大性能问题已得到解决,但仍存在一些与语法、初始值以及结合网格的版本有多容易学习相关的问题。

不过,为了检验我们的假设,我们通过一些示例展示了 Masonry 在每个版本中的运作方式。请查看本博文中的示例并向我们提供反馈,以便我们做出决定并继续开发此功能。

虽然本文未涵盖所有可能的用例,但很明显,将 Masonry 布局与网格布局分开不会导致该功能缺少任何功能。事实上,情况可能恰恰相反。正如您将在本文中看到的那样,display: masonry 版本带来了新的机遇和更简单的语法。此外,许多开发者还担心,使用 Masonry 重新排序项可能会导致无障碍功能问题。我们还通过提议的 reading-flow 属性解决了这两种语法版本的问题。

基本瀑布流布局

这是大多数人在想到砌块布局时想象的布局。商品按行显示,放置第一行后,后续商品会移到较短商品留下的空间中。

一种具有列的布局,其中的项目填充列时没有间隙。
在此布局中,先定义列,然后以砌墙式布局填充项,而不是严格按行填充。

活动门票提供商:display: masonry

如需创建瀑布流布局,请将 display 属性的值设为 masonry。这会创建一个网格布局,其中包含您定义(或由内容定义)的列轨道,以及另一轴上的网格。第一个项显示在块和内嵌起始位置(因此在英语中为左上角),并且项按内嵌方向布局。

如需定义轨道,请使用 masonry-template-tracks 并提供轨道列表值,如 CSS 网格布局中所用。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(3, 1fr);
  gap: 10px;
}

活动门票提供商:display: grid

如需创建网格布局,请先使用 display 属性的 grid 值创建网格布局。使用 grid-template-columns 属性定义列,然后为 grid-template-rows 赋予 masonry 值。

这样会创建您预期的布局,其中包含自动放置的网格项,但每行中的项会使用瀑布流布局,并会重新排列以占据前一行中较小项留下的空间。

.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: masonry;
  gap: 10px;
}

在两种方案之间进行选择时需要考虑的因素

这两种方法的一个显著区别是,使用 display: masonry 版本时,即使您没有使用 masonry-template-tracks 指定任何轨道,也会获得砌体布局。因此,您可能只需要 display: masonry。 这是因为 masonry-template-tracks 的初始值为 repeat(auto-areas, auto)。该布局会创建尽可能多的自动调整大小的轨道,以适应容器。

反向流(使用 masonry)

该规范包括更改砌块流方向的方法。例如,您可以更改流程,使其从块末尾向上显示。

一种具有列的布局,其中的项从布局底部开始填充列。
在此布局中,先定义列,然后从块末尾开始按砌块布局填充项。

活动门票提供商:display: masonry

使用 display: masonry 创建瀑布流布局,然后使用值为 column-reversemasonry-direction

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(3, 1fr);
  masonry-direction: column-reverse;
}

活动门票提供商:display: grid

使用 display: gridgrid-template-rows: masonry 创建一个瀑布流布局。 然后,将 grid-auto-flow 属性的新值设为 row-reverse,使项目从网格容器的块末尾开始布局。

.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: masonry;
  grid-auto-flow: row-reverse;
}

在两种方案之间进行选择时需要考虑的因素

display: masonry 版本的运作方式与 flexbox 非常相似。使用值为 column-reversemasonry-direction 属性更改列的流向。

CSS 网格版本使用 grid-auto-flow。按照目前的定义,grid-auto-flow: row-reversegrid-auto-flow: column-reverse 会产生相同的效果。这可能会令人困惑,因为您可能认为它们会执行不同的操作。

行砌体

您还可以更改方向来定义行。

一种具有行的布局,填充行的项之间没有间隙。
在此布局中,先定义行,然后以砌墙式布局填充项,而不是严格按列填充。

活动门票提供商:display: masonry

使用 display: masonry 创建一个网格布局,然后将 masonry-direction 的值设置为 row。除非您希望行具有特定的块大小,否则无需指定任何轨道大小,因为默认值为 auto,因此轨道将根据其包含的内容调整大小。

.masonry {
  display: masonry;
  masonry-direction: row;
}

活动门票提供商:display: grid

.masonry {
  display: grid;
  grid-template-columns: masonry;
  grid-template-rows: repeat(3, 1fr);
}

在两种方案之间进行选择时需要考虑的因素

与反向流程一样,将 display: masonry 版本从列更改为行意味着更改 masonry-direction 的值。对于网格版本,您需要切换 grid-template-columnsgrid-template-rows 属性的值。或者,如果使用简写形式,请更改语法顺序。

在这两个切换流程示例中,display: masonry 版本都更直观。有一个属性 masonry-direction 用于控制流量,它接受以下值之一:

  • row
  • column
  • row-reverse
  • column-reverse

然后,您可以根据需要向 masonry-template-tracks 添加任何尺寸信息,前提是默认的自动值不符合您的需求。

对于网格,如需反向排列,您需要使用 grid-auto-flow 属性;如需进行行砌体切换,请切换 grid-template-* 属性的值。在当前的网格语法中,也无法将网格轴的值保留为未定义。您始终需要在没有 masonry 值的轴上指定 grid-template-* 属性。

放置商品

在这两个版本中,您都可以使用网格布局中熟悉的基于线的放置方式来明确放置项。在这两个版本中,您只能在网格轴(即具有预定义轨道的那条轴)上定位项,而无法在执行瀑布流布局的轴上定位项。

活动门票提供商:display: masonry

以下 CSS 定义了一个包含四列的网格布局。因此,网格轴为列。具有 a 类的项从第一列线放置到第三列线,跨越两个轨道,并具有新的 masonry-track-* 属性。也可以将其定义为 masonry-track: 1 / 3; 的简写形式。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(4, 1fr);
}

.a {
  masonry-track-start: 1;
  masonry-track-end: 3;
}

活动门票提供商:display: grid

以下 CSS 定义了一个包含四列的网格布局。因此,网格轴为列。具有 a 类的项从第一列线放置到第三列线,跨越两个轨道,并具有 grid-column-* 属性。也可以将其定义为 grid-column: 1 / 3; 的简写形式。

如果网格轴是列,系统会忽略 grid-row-* 属性;如果网格轴是行,系统会忽略 grid-columns-* 属性。

.masonry {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: masonry;
}

.a {
  grid-column-start: 1;
  grid-column-end: 3;
}

您可以使用这两种语法来命名线条。以下示例展示了一个网格,其中包含两条名为 a 的列线。

活动门票提供商:display: masonry

命名行在 masonry-template-tracks 的轨道列表值中定义。该项可以放置在任何名为 a 的行之后。

.masonry {
  display: masonry;
  masonry-template-tracks: 100px [a] auto [a] auto 100px;
}

.item {
  masonry-track: a;
}

活动门票提供商:display: grid

命名行在 grid-template-columns 的轨道列表值中定义。该项放置在名为 a 的第一行之后。如果定义了 grid-row 属性,系统会忽略该属性。

.masonry {
  display: grid;
  grid-template-columns: 100px [a] auto [a] auto 100px;
  grid-template-rows: masonry;
}

.item {
  grid-column: a;
  grid-row: a; /* ignored */
}

您还可以在这两种语法中使用命名区域。以下示例展示了一个包含三个轨道(名为“a”“b”和“c”)的网格。

活动门票提供商:display: masonry

轨道名称与 masonry-template-areas 的值相同。由于未定义任何轨道大小,因此所有三个轨道的大小都默认为 auto。该项放置在“a”轨道中。

.masonry {
  display: masonry;
  masonry-template-areas: "a b c";
}

.item {
  masonry-track: a;
}

无论您是定义行还是列,此方法都适用;唯一的区别在于 masonry-direction 属性。

活动门票提供商:display: grid

对于,语法基本相同。同样,由于未定义轨道大小,因此所有三个轨道都默认为 auto 大小,但您仍需明确声明另一个轴为 Masonry:

.masonry {
  display: grid;
  grid-template-areas: "a b c";
  grid-template-rows: masonry;
}

.item {
  grid-column: a;
}

不过,对于,值的写入方式必须有所不同,因为 grid-template-areas 实际上定义了一个二维区域,并且每行都作为单独的字符串写入:

.masonry {
  display: grid;
  grid-template-areas: "a" "b" "c"; /* Note the difference, each row is quoted. */
  grid-template-columns: masonry;
}

.item {
  grid-row: a;
}

在两种方案之间进行选择时需要考虑的因素

无论采用哪种定位方式,在切换方向时,display: masonry 语法的效果都更好。由于 masonry-track-* 属性在网格轴的任一方向上均有效,因此您只需更改 masonry-direction 的值即可更改方向。对于网格版本,您至少需要冗余属性才能启用切换。不过,请参阅前面的示例,了解在网格版本中更改方向的其他方式,这些方式更为复杂。

简写形式

在此博文中,我们使用了全写形式,以便更清楚地了解正在使用的属性,不过 display: masonrydisplay: grid 版本都可以使用简写形式来定义。

活动门票提供商:display: masonry

display: masonry 简写形式使用 masonry 关键字。如需创建基本的 Masonry 布局,请使用以下 CSS:

.masonry {
  display: masonry;
  masonry: repeat(3, 1fr);
}

如需创建简单的基于行的 Masonry 布局,请执行以下操作:

.masonry {
  display: masonry;
  masonry: row;
}

使用简写定义轨道和基于行的布局:

.masonry {
  display: masonry;
  masonry: repeat(3, 1fr) row;
}

活动门票提供商:display: grid

使用 grid 简写创建基本的 Masonry 布局。

.masonry {
  display: grid;
  grid: masonry / repeat(3, 1fr);
}

如需创建简单的基于行的 Masonry 布局,请执行以下操作:

.masonry {
  display: grid;
  grid: repeat(3, auto) / masonry;
}

在更复杂的示例中,由于 display:masonry 语法的整体结构更简单,因此可以将更多属性打包到简写形式中,而不会变得过于复杂。

例如,假设您创建了三个名为“a”“b”和“c”的列,并从底部向上填充。

活动门票提供商:display:masonry

display: masonry 中,这三者可以一起通过简写形式进行设置:

.masonry {
  display: masonry;
  masonry: column-reverse "a b c";
}

由于它们是自动调整大小的,因此您无需指定大小,但如果您想要特定大小,也可以添加。例如:masonry: column-reverse 50px 100px 200px "a b c";

此外,每个组件都可以随意重新排序;您无需记住任何特定顺序。如果您想改为按行操作,只需将 column-reverse 替换为 rowrow-reverse,其余语法保持不变。

活动门票提供商:display: grid

display: grid 中,必须分别设置这三个方面:

.masonry {
  display: grid;
  grid-template-rows: masonry;
  grid-template-areas: "a b c";
  grid-auto-flow: wrap-reverse;
}

与砌墙示例类似,这会将所有列设置为 auto 大小,但如果您想提供明确的大小,可以这样做:

.masonry {
  display: grid;
  grid: masonry / 50px 100px 200px;
  grid-template-areas: "a b c";
  grid-auto-flow: wrap-reverse;
}

或者,如果您想使用“网格”来同时设置大小和区域名称,可以这样做:

.masonry {
  display: grid;
  grid: "a b c" masonry / 50px 100px 200px;
  grid-auto-flow: wrap-reverse;
}

在这两个示例中,顺序是严格要求的,如果您想要的是行,则顺序会有所不同。例如,更改为行后的效果如下所示:

.masonry {
  display: grid;
  grid: 50px 100px 200px / masonry;
  grid-template-areas: "a" "b" "c";
}

或者,用一个简短的公式来表示所有这些关系:

.masonry {
  display: grid;
  grid: "a" 50px "b" 100px "c"  200px / masonry;
}

在两种方案之间进行选择时需要考虑的因素

鉴于 display: masonry 是一种相对简单的简写形式,因此可能会得到广泛使用。在许多情况下,对于“标准”砌块布局,您只需设置轨道定义;所有其他值都可以采用默认值。

display: grid 版本使用现有的 grid 简写,这是一种相当复杂的简写,根据我们的经验,开发者不太常用。如前面的示例所示,即使用于简单的网格布局,在设置值的顺序时也需要谨慎。

其他注意事项

本文将介绍一些常见的用例,但我们不知道网格或瀑布流布局在未来会如何发展。使用单独的 display: masonry 语法的一个重要理由是,它允许这两个语法在未来出现差异。特别是对于初始值(例如 masonry-template-tracks 的初始值),在 Masonry 中执行的操作可能与在网格中执行的操作不同。如果我们采用 display: grid 版本,就无法更改网格默认值,这可能会限制我们未来想要做的事情。

在这些示例中,您可以看到在使用 Masonry 时,浏览器必须忽略网格中有效的属性。例如,在 grid-template-areas 中,由于它定义了二维网格布局,因此大多数值都会被舍弃,而在 Masonry 中,我们仅完全定义了一个方向。

提供反馈

请查看以下示例,以及将每个版本并列显示的规范草稿。欢迎在问题 9041 中发表您的看法。如果您想在自己的博客或社交媒体上撰写帖子,请务必在 XLinkedIn 上告知我们。