【外评】CSS masonry 砌体布局的替代建议

Chrome 团队非常希望能在网站上实现砌体类型布局。不过,我们认为在近期的 WebKit 博文中提议的 CSS 网格规范中实现此功能是错误的。我们还觉得 WebKit 帖子反对无人提议的砌体版本。

因此,本博文旨在介绍 Chrome 团队为何对在 CSS 网格布局规范中实现砌体有疑问,并确切阐明备选方案可实现的功能。简而言之:

  • Chrome 团队非常渴望解开砖石封堵,我们知道这也是开发者的需求。
  • 除了您认为砌体是否为网格之外,在网格规范中添加砌体会出现问题。
  • 在网格规范之外定义砌体不会阻止砌体有多个轨迹尺寸,也不能阻止使用对齐或间隙等属性,或网格布局中使用的任何其他特征。

Chrome 团队认为,砌体应该是一种单独的布局方法,使用 display: masonry 进行定义(或者,应根据其他关键字来决定更好的名称)。在这篇博文的后面部分,您可以通过一些示例代码了解上述代码的含义。

我们认为在网格布局之外更好地定义砌体,原因有两个:一是可能存在布局性能问题;二是砌体和网格在一种布局方法中具有意义,但在另一种布局方法中却没有意义。

从浏览器处理尺寸和放置方式而言,网格和砌体是相反的。布局网格时,所有项都放置在布局之前,并且浏览器确切地知道每个轨道中的内容。这样一来,就可以实现复杂的固有尺寸,这在网格中非常有用。如果采用砌体,系统会按原样布置物品,浏览器会不知道每个轨道中有多少件物品。不存在所有固有大小的轨道或所有固定大小的轨道的问题,但将固定大小的轨道和固有大小的轨道混合时会导致此问题。为了解决此问题,浏览器需要执行布局前步骤,即以各种可能的方式对各项进行布局以进行测量,而大型网格则会导致布局性能问题。

因此,如果您的砌体布局的轨迹定义为 grid-template-columns: 200px auto 200px(在网格中很常见),那么就会遇到问题。添加子网格后,这些问题将呈指数级

有一种论点,大多数人不会遇到这种情况,但我们已经知道,人们确实有非常大的网格。在有替代方法的情况下,我们不希望发布在使用方法方面受到限制的产品。

当 flexbox 和 grid 成为 CSS 的一部分后,开发者常常会觉得他们的行为方式不一致。他们之所以遇到这种不一致的情况,是因为长期以来对布局如何基于块布局的假设一直以来都有所假设。随着时间的推移,开发者已经开始了解格式设置上下文。当我们切换到网格或灵活格式上下文时,某些行为会有所不同。例如,您知道在 Flexbox 中,并非所有对齐方法都可用,因为 Flexbox 是一维的。

将砌石任务捆绑为网格可以打破格式上下文与对齐属性(详见 Box 对齐规范中按格式上下文定义)可用性之间的这种明确联系。

如果我们决定通过将固有和固定轨道定义在砌体中设为非法的方式来解决之前概述的性能问题,那么您必须记住,非常常见的网格布局模式不适用于砌体。

此外,还有一些模式在砌体中是有意义的,例如 grid-template-columns: repeat(auto-fill, max-content),因为您没有交叉约束条件,但在网格中需要保持无效状态。下面列出了我们预计行为方式不同或具有不同有效值的属性。

  • grid-template-areas:在砌体中,您只能沿非砌体方向指定初始行。
  • grid-template:简写形式需要考虑所有差异。
  • 由于法律值不同,因此跟踪 grid-template-columns 和 grid-template-rows 的大小值。
  • grid-auto-flow 不适用于砌体,masonry-auto-flow 不适用于网格。合并它们会产生因您使用的布局方法导致无效内容的问题。
  • 网格有四个放置属性(grid-column-start 等等),而砌体只有两个。
  • 网格可以使用 justify-* 和 align-* 的全部六个属性,但 Masonry 只使用 Flexbox 这样的子集。

此外,如果开发者使用的值在加砌网格或非砌体网格中无效,则还需要说明在发生所有新错误情况下会发生什么情况。例如,可以使用 grid-template-columns: masonry 或 grid-template-rows: masonry,但不能同时使用这两者。如果同时使用这两者,会出现什么情况? 必须指定这些详细信息,以便所有浏览器都执行相同的操作。

无论是现在还是将来,从规范的角度来看,这一切都会变得非常复杂。我们需要确保所有要素都考虑到砌体,以及它是否适用于砌体。对于开发者来说,这也令人感到困惑。为什么您应该谨记,尽管使用 display: grid,但有些地方因使用砌体而不起作用?

如前所述,Chrome 团队希望在网格规范之外定义砌体。这并不意味着可以使用列大小相同的非常简单的布局方法。WebKit 博文中的所有演示仍然可行。

大多数人想到砌体时,都会想到具有多个列相等的布局。这将使用以下 CSS 进行定义,该 CSS 需要比等效的网格捆绑版本的代码更少。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(auto-fill, minmax(14rem, 1fr));
  gap: 1rem;
}

除了前面提到的固有和固定轨道大小混合问题之外,您还可以使用网格中您喜欢的所有轨道大小。例如 WebKit 博文中的示例,这是一种重复较窄列宽列的模式。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(auto-fill, minmax(8rem, 1fr) minmax(16rem, 2fr)) minmax(8rem, 1fr);
  gap: 1rem;
}

因为网格是二维布局方法,所以我们不允许在网格中使用其他轨迹大小调整选项。这些模型在砌石中很有用,但如果它们不适用于网格,就会感到困惑。

正在自动填充 max-content 个大小的轨道。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(auto-fill, max-content);
  gap: 1rem;
}

正在自动填充 auto 大小的轨道,这将创建大小相同的轨道,并自动调整尺寸以容纳最大的轨道。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(auto-fill, auto);
  gap: 1rem;
}

没有理由让内容跨越单独的砌体规范中的列。这可能会使用 masonry-track 属性,它是 masonry-track-start 和 masonry-track-end 的简写形式,因为在砌体布局中,您只有一个维度可以跨越对象。

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(auto-fill, auto);
}

.span-2 {
  masonry-track: span 2; /* spans two columns */
}

.placed {
  masonry-track: 2 / 5; /* covers tracks 2, 3, and 4 */
}

这可以通过单独的砌体规范提供支持,但也不允许混合使用固有尺寸轨道和固定尺寸轨道。到底是什么样子需要进行定义。我们没有理由认为这种做法会奏效。

我们希望能够达到可以互操作性的规范。不过,我们希望以一种当前和未来均能运行良好且可供开发者信赖的方式实现这一目标。处理所述性能问题的唯一方法是让第二个问题(即在砌体中使网格的某些部分不合法)变得更糟。我们认为这并不是一个好解决方案,尤其是当您可以拥有所有需要的网格功能,同时将不同的内容明确分开时。

如果您有任何反馈,请加入问题 9041 中的讨论。

感谢 Bramus、Tab Atkins-Bittner、Una Kravets、Ian Kilpatrick 和 Chris Harrelson 对这篇博文的审核以及由此产生的相关讨论。

本文文字及图片出自 An alternative proposal for CSS masonry

你也许感兴趣的:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注