CSS 中的砌体布局:Grid 应进化还是为新模块让路?
近期,CSS 中新增砌体式布局支持的提案出现分歧。一方提议扩展现有的 CSS Grid 规范,另一方则建议将砌体布局设为独立模块。而最近,苹果 WebKit 团队提出了第三种方案——“Item Flow”。本文将详细探讨这三种方案。
如果你需要构建类似 Pinterest 的布局,但厌倦了 JavaScript,CSS 是否终于能提供解决方案?初看 Pinterest 的页面,你可能会认为 CSS 网格布局就足够了,但实际构建时才会发现仅靠 display: grid 和一些调整是远远不够的。事实上,Pinterest 使用 JavaScript 构建其布局,但如果仅用 CSS 实现,那该多酷?
也许有办法。CSS 网格布局有一个实验性的 grid-template-rows: masonry 值。砌体布局是一种不规则的流动网格。不规则之处在于,砌体布局的下一行项目会上升填充砌体轴上的空间,而不是遵循严格的网格模式并在较短片段后留下空间。它是作品集、图片库和社交信息流的理想选择——这些设计依赖于有机流动。但问题是:虽然这个实验性功能存在(例如在启用标志的 Firefox Nightly 中),但由于有限的浏览器支持和当前形式的一些粗糙边缘,它并不是你期望的无缝解决方案。
也许没有。CSS 缺乏原生砌体支持,迫使开发者使用 hack 或 JavaScript 库(如 Masonry.js)。有良好设计背景的开发人员对 CSS 网格形式的砌体布局提出了批评,例如 Rachel 指出砌体的有机流动与 Grid 的严格二维结构形成对比,可能会让期望 Grid 类似行为的开发者感到困惑;Ahmad Shadeed 抱怨它使网格布局变得比应有的更复杂,可能会让重视 Grid 清晰结构布局的开发者不知所措。Geoff 也附和 Rachel Andrew 的担忧,即“为了理解砌体行为而教授和学习 Grid,不必要地将两种不同的格式化上下文混为一谈”,使依赖清晰心智模型的设计师和开发者的教育复杂化。
也许还有希望。苹果 WebKit 团队刚刚提出了一个新的竞争者,声称不仅将 Grid 和砌体的优点合并为一个统一的系统简写,还包括了 Flexbox 的概念。想象一下,三个 CSS 布局系统的精华合而为一。
鉴于这些抱怨和批评——以及一个新的参与者——问题是:CSS Grid 应该扩展以处理砌体,还是应该由一个全新的专用模块接管,或者 Item Flow 应该接手?
当前 CSS 中砌体的状态
许多开发者尝试使用 CSS Grid 配合手动行跨度 hack、CSS 列和 JavaScript 库来在其 Web 应用中实现砌体布局。没有原生砌体,开发者通常转向像这样的 Grid hack:一个 grid-auto-rows 技巧配合 JavaScript 来模拟流动。它有效——某种程度上——但裂缝很快显现。
例如,下面的示例依赖 JavaScript 在渲染后测量每个项目的高度,计算项目应跨度的 10px 行数(加上间隙),动态设置 grid-row-end,并使用事件监听器在页面加载和窗口调整大小时调整布局。
|
|
|
|
|
|
这个 Grid hack 让我们接近砌体布局——项目堆叠,间隙填充,看起来足够体面。但说实话:它还没有达到。上面的代码示例,与原生 grid-template-rows: masonry(这是实验性的,仅存在于 Firefox Nightly)不同,依赖 JavaScript 计算跨度,违背了“无 JavaScript”的梦想。JavaScript 逻辑通过在调整大小或内容更改时重新计算跨度来工作。正如 Chris Coyier 在对类似 hack 的批评中指出的,这可能导致复杂页面上的延迟。
此外,逻辑 DOM 顺序可能与视觉流不匹配,这是 Rachel Andrew 对砌体布局普遍提出的担忧。最后,如果图像加载缓慢或内容移位(例如,懒加载媒体),跨度需要重新计算,有布局跳动的风险。这并不是理想的 hack;我相信你会同意。
开发者需要流畅的体验,从人体工程学角度来说,用脚本 hack Grid 是一种心理杂耍。它迫使你在 CSS 和 JavaScript 之间切换来调整布局。一个原生解决方案,无论是 Grid 驱动的还是新模块,都必须实现轻松响应、整洁渲染和不破坏工具的工作流程。
“这就是为什么这场辩论很重要——我们的日常工作需要它。
选项 1:扩展 CSS Grid 以支持砌体
一种前进的方式是增强 CSS Grid 的砌体能力。截至本文撰写时,CSS 网格已扩展以容纳砌体。grid-template-rows: masonry 是 CSS Grid Level 3 的草案,目前正在 Firefox Nightly 中进行实验。此布局的列将保持为网格轴,而行则采用砌体。然后,子元素沿着行逐个项目布局,就像网格布局的自动放置一样。使用此布局,项目垂直流动,尊重列轨道但不尊重行约束。
此选项将 Grid 保留为首选布局系统,但允许它处理我们渴望的流动、间隙填充堆栈。
|
|
首先,grid-masonry 风格建立在 CSS Grid 的熟悉性和强大工具(例如,DevTools 支持)之上。作为前端开发者,你可能已经玩过 grid-template-columns 或 grid-area,所以你已经在学习矩阵中走了一半。砌体仅扩展了现有功能,消除了从头学习全新语法的需要。此外,Grid 的强大工具随 Chrome DevTools 的网格覆盖或 Firefox 的布局检查器而来,消除了对 JavaScript hack 的需求。
别太快:有限制。Grid 的规范已经包括 align-content 和 grid-auto-flow 等属性。将砌体堆叠在列表中风险将其变成迷宫。
然后还有边缘情况。当你希望一个项目跨多个列并流动砌体风格时会发生什么?或者当项目之间的间隙在列之间不对齐时?规范在这里仍然模糊,早期测试暗示了错误,例如如果内容动态加载,项目会不可预测地跳跃。这个问题可能会破坏布局,尤其是在响应式设计上。浏览器兼容性问题也存在。它仍然是实验性的,即使有 polyfills,它也不能在除 Firefox Nightly 以外的其他浏览器上工作。不是你会在下一个客户项目中尝试的东西,对吧?
选项 2:独立的砌体模块
如果我们有一个 display: masonry 方法呢?请容忍我几分钟。这不仅仅是 wishful thinking。早期的 CSS 工作组聊天已经提出了这个想法,值得描绘它如何改善布局。让我们深入探讨愿景、它可能如何工作,以及在此过程中的得失。
想象一个布局系统,不依赖 Grid 的刚性轨道或 Flexbox 的线性流,而是在垂直堆叠中蓬勃发展,带有水平扭曲。目标?为砌体的标志性外观提供一个干净的石板:项目级联向下列,自然填充间隙,无需 hack。受 CSSWG 讨论中的低语和 Chrome 团队的替代提案的启发,这个模块将优先考虑流动性 over 结构,为设计师提供一个感觉直观的工具,就像他们追逐的布局一样。想想 Pinterest 但没有 JavaScript 脚手架。
这是推销:一个名为 masonry 的显示值启动一个基于流的系统,其中项目默认垂直堆叠,水平调整以适应容器。你可以用以下简单属性控制方向和间距:
|
|
想要更多控制?假设的额外功能如 masonry-columns: auto 可以模仿 Grid 的 repeat(auto-fill, minmax()),而 masonry-align: balance 可能会平衡列长度以获得抛光外观。它 less about 精确放置(Grid 的优势)and more about 让内容呼吸和流动,适应任何屏幕大小。这里的巨大胜利是与 Grid 的严格顺序 clean break。一个独立的模块保持它们 distinct:Grid 用于顺序,Masonry 用于流动。不再与不太合适的 Grid 属性搏斗;你得到一个为工作量身定制的系统。
当然,并非一帆风顺。一个全新的规范意味着从零开始。浏览器供应商需要团结 behind it,这可能很慢。此外,它可能导致选择 confusion,开发者会问:“我应该用 Grid 还是 Masonry 来做这个画廊?”但听我说:这个提议的模块可能会在澄清之前 muddy the waters,但 after the water is clear,它 safe for use by all and sundry。
Item Flow:统一的布局解决方案
2025 年 3 月,苹果的 WebKit 团队提出了 Item Flow,一个新系统,将 Flexbox、Grid 和砌体的概念统一到一组属性中。与其选择增强 Grid 或创建新的砌体模块,Item Flow 合并了它们的优势,用称为 item-flow 的简写替换了 flex-flow 和 grid-auto-flow。这个系统引入了四个长手属性:
item-direction:控制流动方向(例如,row、column、row-reverse)。item-wrap:管理包裹行为(例如,wrap、nowrap、wrap-reverse)。item-pack:确定包装密度(例如,sparse、dense、balance)。item-slack:调整布局调整的容差,允许项目收缩或移位以适应。
Item Flow 旨在使砌体成为这些属性的自然结果,而不是一个单独的功能。例如,砌体布局可以通过以下方式实现:
|
|
此设置允许项目垂直流动,包裹成列,并紧密包装,模仿砌体的有机排列。密集包装选项,受 Grid 的 auto-flow: dense 启发,重新排序项目以最小化间隙,而 item-slack 可以微调间距以获得视觉平衡。
Item Flow 的承诺在于其广泛 use case。它通过像 Grid 的 nowrap 或 Flexbox 的平衡包装等功能增强了 Grid 和 Flexbox,解决了长期存在的开发者愿望清单。然而,该提案仍在讨论中,像 item-slack 这样的属性由于对非英语母语者的清晰度问题而面临命名辩论。
缺点?Item Flow 是一个面向未来的概念,截至 2025 年 4 月尚未在浏览器中实现。开发者必须等待标准化和采用,并且 CSS 工作组仍在收集反馈。
什么是正确的路径?
虽然没有直接答案,但砌体辩论取决于平衡简单性、性能和灵活性。用砌体扩展 Grid 是诱人的,但风险是使一个已经 robust 的系统 overcomplicating。一个独立的 display: masonry 模块提供了清晰度,但增加了 CSS 的学习曲线。Item Flow,最新的竞争者,提出了一个统一的系统,可以使砌体成为 Grid 和 Flexbox 的自然扩展,可能最终平息辩论。
每种方法都有权衡:
- Grid with Masonry:熟悉但可能笨拙,有可访问性和规范问题。
- 新模块:干净且 purpose-built,但需要学习新语法。
- Item Flow:优雅且多功能,但尚不可用,有关于命名和实现的持续辩论。
Item Flow 增强现有布局同时支持砌体的能力使其成为一个引人注目的选项,但其成功取决于浏览器采用和社区支持。
结论
那么,在这一切之后,我们落在哪里?砌体对决归结为三条路径:将砌体扩展到 CSS Grid 中,砌体的独立模块,或 Item Flow。现在,问题是,CSS 最终会让我们从砌体的 JavaScript 中解放出来,还是我们仍在做梦?
Grid teasing us with a taste,而独立模块 whispering promises——但终点线 unclear,WebKit swoops in with a killer merge shorthand,Item Flow。浏览器 buy-in,社区 push,以及一些更多的规范修订可能会告诉我们。就目前而言,这是你的举动——测试、调整和权衡。答案正在来临,一次一个布局。
参考文献
- “Native CSS Masonry Layout in CSS Grid” by Rachel Andrew
- “Should Masonry be part of CSS Grid?” by Ahmad Shadeed
- “CSS Masonry & CSS Grid” by Geoff Graham
- “Masonry? In CSS?!” by Michelle Barker
- “Native CSS Masonry Layout in CSS Grids” by Chris Coyier
- “Item Flow Part 1: A Unified Concept for Layout” by WebKit
(gg, yk)