发布时间: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-reverse 的 masonry-direction。
.masonry {
display: masonry;
masonry-template-tracks: repeat(3, 1fr);
masonry-direction: column-reverse;
}
活动门票提供商:display: grid
使用 display: grid 和 grid-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-reverse 的 masonry-direction 属性更改列的流向。
CSS 网格版本使用 grid-auto-flow。按照目前的定义,grid-auto-flow: row-reverse 和 grid-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-columns 和 grid-template-rows 属性的值。或者,如果使用简写形式,请更改语法顺序。
在这两个切换流程示例中,display: masonry 版本都更直观。有一个属性 masonry-direction 用于控制流量,它接受以下值之一:
rowcolumnrow-reversecolumn-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: masonry 和 display: 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 替换为 row 或 row-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 中发表您的看法。如果您想在自己的博客或社交媒体上撰写帖子,请务必在 X 或 LinkedIn 上告知我们。