一砖一瓦:帮助我们构建 CSS Masonry

Patrick Brosset
Patrick Brosset
Alison Maher
Alison Maher

发布时间:2025 年 7 月 23 日

Microsoft Edge 和 Google Chrome 团队很高兴地宣布,从 Chrome 和 Edge 140 开始,CSS masonry 已准备就绪,可供开发者进行早期测试。

由于 CSS Masonry 规范和语法仍存在未解决的问题,您的反馈对于帮助我们确定 API 的最终形态至关重要。欢迎试用此功能,并与我们分享您的想法。

立即在 Chromium 中测试 CSS Masonry

如需立即测试 CSS Masonry,请执行以下操作:

  1. 使用 Chrome 或 Edge 140 或更高版本(或其他基于 Chromium 的浏览器,版本相同)。
  2. 在新标签页中前往 about:flags
  3. 搜索“CSS Masonry Layout”。
  4. 启用该标志。
  5. 重新启动浏览器。
实验页面上 Masonry 的条目。

启用此功能后,您可以查看 Microsoft Edge 演示(查看演示源代码)来了解此功能的实际效果,也可以继续阅读以详细了解此功能和可用的语法。

什么是 Masonry?

CSS masonry 是一种布局模式,可让您以类似于砖块的方式排列内容,而这种方式很难通过 CSS 网格、flexbox 或多列布局来实现。

CSS masonry 可用于以列或行格式排列项目,并将项目以折叠方式放置在这些列或行中。

以瀑布流布局排列的商品。

您可以将砌块布局视为高速公路,唯一的限制是不同车道的数量和大小。在轨道内,车辆可以任意长度,并且始终尝试尽可能靠近目的地(即砌块布局的起点)。

使用在车道中排队的车辆演示布局。

布局项仅在一个方向上受到限制,并且可以在另一个方向上自由调整,而无需考虑附近的布局项。与网格不同的是,砌块的轨道仅在一个方向上定义。

在瀑布流布局中,商品的视觉顺序不如最终设计重要。无论您要展示哪些商品,Masonry 都能让您充分利用可用空间。 因此,对于视觉效果要求较高的网页,以及内容视觉顺序不如最终结果重要的网页,这是一个不错的选择。

砌体布局的一个有趣之处在于,它还允许项目跨越多个轨道,就像网格一样。在这种情况下,系统会继续放置商品,尽可能填充可用空间。

这次,包含车辆的图片(这次是大型车辆)占据了两列。

这种自动放置行为可以带来非常有趣的效果,而这正是网页设计师长期以来一直试图实现的目标。例如,您可以查看纽约市照片库演示,了解如何以紧凑的方式在多个列中显示照片,同时允许某些项(在本例中为标题)跨多个列显示:

标题跨列的图库。

以下是其他一些可使用 Masonry 的示例。

一个博客布局,显示每篇博文的缩略图和说明。

一个新闻网站,使用 Masonry 布局来显示文章卡片。
点击此处查看博客演示

一个新闻网站,其中文章以列的形式显示,有些文章比其他文章更宽,而主打图片则占据了整个页面宽度。

新闻网站,其中一些文章跨越多个列。
点击此处查看新闻网站演示

一组照片,列大小各不相同,某些照片跨越多个列。

摄影网站的瀑布流布局。
点击此处观看自然演示视频

解决方法及其限制

目前,在 Web 上实现这种设计模式需要使用 JavaScript 库或采用使用 CSS 网格、Flexbox 或多列的变通方法。不过,这样做也有一些缺点,包括:

  • 性能较差:依靠 JavaScript 库或自定义代码来模拟 CSS 砌块布局会带来性能方面的权衡,从而导致负面的用户体验。
  • 代码复杂性较高
    • 要保证在 CSS 网格、Flexbox 或多列中正确放置项并分配空间,以模拟 CSS Masonry 布局,很难实现。
    • 处理跨多列或多行的商品、自定义商品排序或调整到视口等特定功能也可能会导致复杂性和限制。
  • 维护负担更重:复杂的自定义 CSS 或 JavaScript 代码更难维护。

CSS 网格是一种出色的布局模式,非常灵活,可让您创建许多不同样式的布局,无论是整个网页、组件,还是仅用于对齐各个元素。不过,它不具备与砌块相同的特征。

在 CSS 网格中,行和列是严格定义的,并且项只能存在于网格单元格内。如果您尝试沿某个轴打包商品,但商品尺寸不适合其各自的单元格,则必须选择在商品之间留出间隙,或拉伸商品以填充空白空间。

网格将项放置在固定的轨道中。

与 Masonry 类似,Flexbox 只关心一个方向,并让内容决定它们在另一个方向上要占用的空间。这意味着,只要您愿意让各项按块方向(一次一列)进行布局,就可以使用 Flexbox 获得看起来像砌块布局的布局。Flex 容器还需要定义块大小或高度,以使内容换行到新的 Flex 行,从而创建新列。

Flex 布局按列对内容进行排序。

多列还可以创建看起来像砌体的布局,同样是将项目排列在列中。此外,多列布局不允许您以不同方式调整每列的大小。它们的大小都相同,而 Masonry 在定义放置项的轨道方面提供了很大的灵活性。

这里需要记住的是,网格、Flexbox 或多列布局并不比 Masonry 布局差。它们是非常出色的布局类型,可用于多种使用情形。重点是:如果您想要的是瀑布流布局,那么 CSS 瀑布流布局就能满足您的需求。

CSS Masonry 的发展现状

CSS 工作组正在 CSS 网格级别 3 规范中起草砌块布局。该规范仍在建设中,目前暂时包含两种不同的建议语法。第一种方法为 display 属性使用了一个新关键字,而第二种方法则将 Masonry 直接集成到 CSS 网格布局中。

使用 display: masonry

此语法将 CSS 砌块作为自己的 display 类型引入。如需详细了解此方法及其动机,请参阅 Google Chrome 团队的博文需要反馈:我们应如何定义 CSS Masonry?以及本文的其余部分。Chromium 中的当前原型基于此提案。

display: grid; grid-template-*: masonry;

在此语法中,CSS 砌块直接集成到 CSS 网格中。在基于行的 Masonry 布局中,通过将关键字 masonry 应用于 grid-template-columns 定义来触发 Masonry 模式;在基于列的 Masonry 布局中,通过将关键字 masonry 应用于 grid-template-rows 定义来触发 Masonry 模式。

如需详细了解此提案及其动机,请参阅 WebKit 博文帮助我们为 CSS 中的 Masonry 选择最终语法

请注意,此提案的替代方案是 item-pack 属性collapse 关键字,它们会触发 CSS 砌块布局,而不是使用两个网格模板属性之一。

自 Chrome 和 WebKit 团队发布博文以来,CSSWG 一直在讨论要采用的总体语法。您的反馈有助于我们进一步开发这些论坛。

如需详细了解当前讨论的状态,请参阅问题 11593,其中概述了当前的一组 masonry 语法讨论主题;另请参阅问题 11243,其中总结了迄今为止的语法辩论。

创建自己的 CSS 网格布局

让我们来玩点有趣的,创建一个 CSS 砌块布局。

虽然 CSS Masonry 的语法仍在讨论中,但您可以在 Chromium 中启用 CSS Masonry 布局标志来测试该功能,如立即测试 CSS Masonry 中所述。以下示例演示了开发者试用版中提供的功能。

创建 Masonry 容器

如需创建第一个基于列的 Masonry 容器,请使用 display:masonry 并使用 grid-template-columns 定义列大小。由于 masonry-direction 默认为 column,因此设置此属性是可选的。

.masonry {
  display: masonry;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
}
所有列大小相同的 Masonry 布局。
点击此处查看等宽列演示

对于基于行的 Masonry 容器,请改用 display:masonry,使用 grid-template-rows 定义行大小,然后设置 masonry-direction:row

.masonry {
 display: masonry;
 masonry-direction: row;
 grid-template-rows: repeat(auto-fit, minmax(160px, 1fr));
 gap: 10px;
}
所有行大小相同的 Masonry 布局。
点击此处查看等高行演示

您可能已经注意到,此语法与 Google 的原始提案略有不同。无论 CSS Masonry 使用何种触发器,CSS 工作组都已决定在 CSS Masonry 布局中重用网格模板大小调整和放置属性

虽然这有助于在布局类型之间更好地重用属性,但您可能会觉得这令人困惑,我们很乐意听取您对此主题的意见。我们可能会探索为 grid-template-columnsgrid-template-rows 等属性创建更通用的别名,例如 template-columnstemplate-rows,这些别名可用于网格和瀑布流。

使用默认轨道大小

随着新的展示广告类型的推出,我们有机会重新思考媒体资源默认设置。

在网格中,grid-template-columnsgrid-template-rows 默认值为 none,按照目前的定义,这通常会生成单列或单行。对于 Masonry 布局,此默认值通常会导致布局不理想。

Chromium 中的实现添加了针对 none 的新提议定义,该定义将替换 CSS 网格布局中的默认轨道大小。此新默认轨道大小为 repeat(auto-fill, auto) 值。此值可创建出色的网格布局,而无需定义轨道大小:

.masonry {
  display: masonry;
  gap: 10px;
}
具有自动调整大小的列的 Masonry 布局。
点击此处查看默认轨道大小演示

如图所示,砌块容器会创建尽可能多的自动调整大小的列,以填充可用空间。

使用 CSS 网格时,所有项目都会在轨道确定尺寸之前放置,这意味着无法实现这种轨道自动调整尺寸定义。不过,使用 CSS 砌块布局后,此限制不再适用,因为放置和调整大小是相互关联且简化的。解除此限制后,我们可以为网格布局提供更有用的轨道默认大小。

尝试使用 masonry 简写属性

如前所述,Chromium 中的当前实现依赖于 grid-template-* 属性来定义布局中的 Masonry 轨道。不过,由于 Masonry 只有一个维度,我们还实现了 masonry 简写属性,您可以使用该属性一次性定义 Masonry 方向和轨道定义,而无需使用令人困惑的 grid- 前缀属性。

例如,以下两个代码段将创建等效的 CSS Masonry 容器。

.masonry {
 display: masonry;
 masonry: "a a b" 50px 100px 200px row;
}

.masonry {
  display: masonry;
  masonry-direction: row;
  grid-template-rows: 50px 100px 200px;
  grid-template-areas: "a" "a" "b"
}
砌块布局,其中包含三行,且行的高度逐渐增大。
点击此处查看 masonry 简写演示

CSS 工作组仍在讨论 masonry 简写属性。欢迎立即试用,并与我们分享您的想法。

使用自定义轨道大小

在定义轨道大小时,在让您微调布局轨道的数量和大小方面,砌块布局与网格布局一样灵活。砌块轨道也不必都具有相同的大小,例如:

.masonry {
 display: masonry;
 masonry: repeat(2, 3rem) repeat(auto-fit, 5rem) 12rem;
}
具有各种不同轨道尺寸的 Masonry 布局。
点击此处查看自定义轨道大小演示

在此示例中,我们定义了两个 3rem 的轨道,后面是数量不等的 5rem 轨道,最后是一个 12rem 的轨道。

跨多个轨道

在 Masonry 中,商品不必受限于其放置的轨道,因为它们可以根据需要跨越多个轨道。当某些商品比其他商品更重要且需要更多空间时,此功能非常有用。

例如:

.masonry {
  display: masonry;
  masonry: repeat(auto-fill, minmax(12rem, 1fr));
}

.important-item {
  grid-column: span 2;
}
包含跨多个轨道的内容的 Masonry 布局。
点击此处查看跨多个轨道演示

您还可以使用此功能跨越多个轨道,使某些项占据容器的整个长度:

.masonry {
 display: masonry;
 masonry: repeat(auto-fill, minmax(12rem, 1fr));
}

.full-bleed {
 grid-column: 1 / -1;
}

新闻网站演示版就是使用此功能在文章中显示订阅广告。

新闻网站布局,横幅覆盖整个区域。

微调 Masonry 项放置位置

在 CSS Masonry 中,内容会放置在运行位置最短的列或行中。

假设有一个两列的 Masonry 容器。如果容器的第一列中有一个高度为 110 像素的项,第二列中有一个高度为 100 像素的项,那么第三个项将放置在第二列中,这样它会更靠近砌筑方向的起点(近 10 像素)。

双列瀑布流布局。

如果您认为 10 像素的运行位置差异对于您的情形来说足够小,并且希望将第三个项目放置在第一列中,以便更好地与源顺序匹配,请使用 item-tolerance 属性。

新的 item-tolerance 属性用于控制商品放置的敏感度。

在上面的示例中,您可以将 item-tolerance: 10px; 应用于容器,以自定义商品放置位置的可变性:

.masonry {
  display: masonry;
  masonry: 200px 200px;
  gap: 10px;
  item-tolerance: 10px;
}
两列的瀑布流布局。
点击此处查看商品容差演示

请注意,草稿规范将此属性称为 item-slack。CSS 工作组最近决定改用 item-tolerance 作为名称,规范很快就会更新。

其他可用媒体资源

您可以像使用 CSS 网格一样,使用相同的模板尺寸和放置属性来调整和放置砌体容器网格轴中的项目,例如 grid-rowgrid-columngrid-areagrid-template-areasorder。 在创建瀑布流布局时,充分体验 CSS 网格的强大功能。

征求反馈

我们迫不及待地想让您探索 CSS Masonry,发挥创意,并发现它能帮助您解锁哪些新功能。一个不错的入门方法是查看我们的演示及其源代码,然后在 Chromium 中开始构建自己的示例(请记得先启用标志)。

您的反馈对我们至关重要,有助于我们完善 API 并确保其设计能够满足您在网络上的需求。欢迎试用 Masonry,并与我们分享您的想法!

如果您对 API 的形态有任何想法或反馈,请在问题 11243 中发表评论告诉我们;如果您想在自己的博客或社交媒体上撰写帖子,请务必在 XLinkedIn 上告知我们。

Chromium 中仍在实现 CSS masonry。如果您确实要测试此功能,请注意我们仍在积极开发此功能,您可能会遇到此功能无法按预期运行的情况。当前的一些限制包括密集打包、反向放置、子网格支持、非正常流支持、基准支持、开发者工具支持、碎片支持、间隙装饰支持等。

如果您在测试该功能时发现 bug,请通过打开新的 Chromium bug 来分享您的反馈。