CSS 中的砌体布局:Grid 应该进化还是为全新模块让路?
目前围绕在 CSS 中添加砌体(Masonry)样式布局的支持,存在多个相互竞争的建议。一方提出扩展现有的 CSS Grid 规范,另一方则建议将砌体布局设立为一个独立的模块。而最近,苹果 WebKit 团队提出了第三个选项——“Item Flow”。前两方各有充分理由,第三方则将它们融合为一,本文将详细介绍这些内容。
如果你需要构建一个类似 Pinterest 风格的布局,但又厌倦了使用 JavaScript,那么 CSS 是否终于能提供解决方案?对于初学者而言,乍看 Pinterest 页面的图钉布局,你可能会认为 CSS 网格布局就足够了,但直到实际构建时才会发现,仅靠 display: grid
加上额外调整是远远不够的。实际上,Pinterest 是使用 JavaScript 构建其布局的,但如果仅用 CSS 就能实现,那该有多酷?如果有一个 CSS 显示属性能够无需任何额外 JavaScript 就提供这样的布局,那该有多棒?
也许有。CSS 网格布局有一个实验性的 grid-template-rows: masonry
值。砌体布局是一种不规则的、流动的网格。所谓不规则,是指与遵循严格网格模式并在较短内容后留下空白的布局不同,砌体布局中下一行的项目会上升以填充砌体轴上的空白。这对于作品集、图片库和社交信息流来说是理想的选择——这些设计依赖于有机的流动。但问题是:虽然这个实验性功能存在(例如在启用标志的 Firefox Nightly 中),但由于浏览器支持有限且当前形式存在一些粗糙之处,它并不是你想象中的无缝解决方案。
也许没有。CSS 缺乏原生的砌体支持,迫使开发者使用 Hack 或 JavaScript 库(如 Masonry.js)。具有良好设计背景的开发者也对 CSS Grid 形式的砌体布局提出了批评,例如 Rachel 指出砌体的有机流动与 Grid 严格的二维结构形成对比,可能会让期望 Grid 类似行为的开发者感到困惑;Ahmad Shadeed 则抱怨它使网格布局变得比应有的更复杂,可能会让重视 Grid 清晰结构布局的开发者不知所措。Geoff 也附和了 Rachel Andrew 的担忧,即“为了理解砌体行为而教授和学习 Grid,不必要地将两种不同的格式化上下文混为一谈”,这使依赖清晰心智模型的设计师和开发者的教育复杂化。
也许还有希望。苹果 WebKit 团队刚刚提出了一个新的竞争者,声称不仅将 Grid 和砌体的优点合并为一个统一的系统简写,还包含了 Flexbox 的概念。想象一下,三个 CSS 布局系统的精华合而为一。
鉴于这些抱怨和批评——以及一个新的参与者——问题是:CSS Grid 应该扩展以处理砌体布局,还是应该由一个全新的、专门的模块接管,或者应该由 Item Flow 来主导?
当前 CSS 中砌体布局的现状
许多开发者尝试使用 CSS Grid 配合手动行跨度 Hack、CSS 多列(Columns)和 JavaScript 库,在他们的网页应用中创建变通方案来实现砌体布局。没有原生砌体支持,开发者通常转向像这样的 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-砌体风格建立在 CSS Grid 的熟悉度和强大工具(例如,DevTools 支持)之上。作为前端开发者,你可能已经玩过 grid-template-columns
或 grid-area
,所以你已经 halfway up the learning matrix。砌体布局仅扩展了现有功能,消除了从头学习全新语法的需要。此外,Grid 的强大工具随 Chrome DevTools 的网格覆盖或 Firefox 的布局检查器一起提供,消除了对 JavaScript Hack 的需求。
别太快:存在限制。Grid 的规范已经包含了诸如 align-content
和 grid-auto-flow
等属性。将砌体布局堆叠在列表中可能使其变成迷宫。
然后还有边缘情况。当你希望一个项目跨多个列并以砌体样式流动时会发生什么?或者当项目之间的间隙在列之间不对齐时?规范在这里仍然模糊,早期测试暗示了错误,例如如果内容动态加载,项目会不可预测地跳跃。这个问题可能会破坏布局,尤其是在响应式设计上。浏览器兼容性问题也存在。它仍然是实验性的,即使有 Polyfill,它也只能在 Firefox Nightly 上工作,而不能在其他浏览器上工作。这不是你想在下一个客户项目中尝试的东西,对吧?
选项 2:独立的砌体模块
如果我们采用 display: masonry
方法呢?请容我几分钟。这不仅仅是 wishful thinking。早期的 CSS 工作组讨论已经提出了这个想法,并且值得设想它如何改进布局。让我们深入探讨这个愿景,它可能如何工作,以及在这个过程中获得或失去什么。
想象一个布局系统,它不依赖于 Grid 的刚性轨道或 Flexbox 的线性流,而是在垂直堆叠中蓬勃发展,带有水平扭曲。目标?为砌体的标志性外观提供一个干净的石板:项目级联向下排列,自然填充间隙,无需 Hack。受 CSSWG 讨论中的低语和 Chrome 团队替代提案的启发,这个模块将优先考虑流动性 over structure,为设计师提供一个感觉直观的工具,就像他们追求的布局一样。想想 Pinterest,但没有 JavaScript 脚手架。
这是推销:一个名为 masonry
的显示值启动了一个基于流的系统,其中项目默认垂直堆叠,水平调整以适应容器。你可以用以下简单属性控制方向和间距:
|
|
想要更多控制?假设的额外功能如 masonry-columns: auto
可以模仿 Grid 的 repeat(auto-fill, minmax())
,而 masonry-align: balance
可能会平衡列长度以获得 polished look。它 less about precise placement(Grid 的优势)and more about letting content breathe and flow,适应任何屏幕尺寸。这里的巨大胜利是与 Grid 的严格顺序 clean break。一个独立的模块使它们保持 distinct:Grid 用于 order,Masonry 用于 flow。不再与不太合适的 Grid 属性搏斗;你得到一个为工作量身定制的系统。
当然,并非一帆风顺。一个全新的规范意味着从零开始。浏览器供应商需要团结 behind it,这可能很慢。此外,它可能会导致选择 confusion,开发者会问诸如:“我应该使用 Grid 还是 Masonry 来构建这个画廊?”但请听我说:这个提议的模块可能会在澄清之前 muddy the waters,但在水清澈之后,它就可以 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 的 promise 在于其广泛 use case。它通过诸如 Grid 的 nowrap 或 Flexbox 的平衡包装等功能增强了 Grid 和 Flexbox,解决了长期存在的开发者愿望清单。然而,该提案仍在讨论中,并且像 item-slack
这样的属性由于对非英语母语者的清晰度问题而面临命名辩论。
缺点?Item Flow 是一个面向未来的概念,截至 2025 年 4 月尚未在浏览器中实现。开发者必须等待标准化和采用,并且 CSS 工作组仍在收集反馈。
哪条是正确的道路?
虽然没有直接答案,但砌体辩论的关键在于平衡简单性、性能和灵活性。使用砌体扩展 Grid 很诱人,但有可能使已经 robust 的系统 overcomplicating。一个独立的 display: masonry
模块提供了清晰度,但增加了 CSS 的学习曲线。Item Flow,最新的竞争者,提出了一个统一的系统,可以使砌体成为 Grid 和 Flexbox 的自然扩展, potentially putting the debate to rest at last。
每种方法都有权衡:
- Grid with Masonry:熟悉但 potentially clunky,存在可访问性和规范问题。
- New Module:干净且 purpose-built,但需要学习新语法。
- Item Flow:优雅且 versatile 但尚不可用,存在命名和实现的持续辩论。
Item Flow 在增强现有布局的同时支持砌体的能力使其成为一个 compelling option,但其成功取决于浏览器采用和社区支持。
结论
那么,在这一切之后,我们落在哪里?砌体对决归结为三条路径:将砌体扩展到 CSS Grid 中,一个独立的砌体模块,或 Item Flow。现在的问题是,CSS 最终会让我们从 JavaScript 中解放出来实现砌体布局,还是我们仍在做梦?
Grid 用 taste teasing 我们,一个独立的模块 whispering promises——但 finish line unclear,而 WebKit swoops in with a killer merge shorthand, Item Flow。浏览器的支持、社区的推动以及一些更多的规范修订可能会告诉我们答案。就目前而言,这是你的行动——测试、调整和权衡。答案正在到来,一次一个布局。
参考文献
- “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