如何用 Material UI 的 Masonry 组件搭建响应式瀑布流布局(含 SSR 场景)?
2026/9/9 16:26:45 网站建设 项目流程

如何用 Material UI 的 Masonry 组件搭建响应式瀑布流布局(含 SSR 场景)?

【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui

如果你的页面里有一批宽度一致、高度各不相同的卡片或图片,需要按“瀑布流”方式排列,Material UI 提供的Masonry组件可以直接完成这件事。它在@mui/lab包中,把任意子元素(包括<div /><img />)排成宽度相同、高度可变的列块,列与列之间的间距可配置。本文按官方文档docs/data/material/components/masonry/masonry.md及其示例代码,给出从基础布局到响应式列数/间距、再到服务端渲染(SSR)场景的完整搭建过程。

先了解 Masonry 的排列规则

官方文档对 Masonry 的布局规则描述如下:

  • Masonry 维护一组宽度一致、高度各异的内容块,内容按行排布;
  • 当某一行的列数达到columns指定的数量后,下一个元素会进入新的一行,并加入当前最短的列,以优化空间利用;
  • Masonry是一个容器,可以接收任意元素作为子项。

这条“总是加入最短列”的规则是后面验证布局是否符合预期的依据:如果某个元素没有落到当前最短的列,说明组件没有正确工作或被外部样式干扰了。

准备依赖

官方示例代码中的导入方式是:

import Masonry from '@mui/lab/Masonry'; import Box from '@mui/material/Box'; import Paper from '@mui/material/Paper'; import { styled } from '@mui/material/styles';

即项目需要依赖@mui/lab(Masonry 所在包)与@mui/material(Box、Paper 等示例中使用的基础组件)。请确认你的package.json中已包含这两个包后再开始下面的步骤。

搭建基础瀑布流

对应官方示例 BasicMasonry.tsx:

import Box from '@mui/material/Box'; import { styled } from '@mui/material/styles'; import Paper from '@mui/material/Paper'; import Masonry from '@mui/lab/Masonry'; const heights = [150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80]; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(0.5), textAlign: 'center', color: (theme.vars || theme).palette.text.secondary, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); export default function BasicMasonry() { return ( <Box sx={{ width: 500, minHeight: 393 }}> <Masonry columns={4} spacing={2}> {heights.map((height, index) => ( <Item key={index} sx={{ height }}> {index + 1} </Item> ))} </Masonry> </Box> ); }

关键配置:

  • columns={4}:固定为 4 列;
  • spacing={2}:元素之间的间距。注意文档明确指出,传给spacing的值会乘以主题中的 spacing 字段(即theme.spacing(2)),而不是 2 像素;
  • 子项通过sx={{ height }}给定不同高度,模拟真实业务中高度不一的卡片。

验证方式:渲染后每一行应恰好容纳 4 个等宽项,项高各不同;第 5 个及之后的项应出现在当前最短的列的下方。heights数组中的具体数值是文档示例数据,你可以替换为自己的内容,验证时以“列宽一致 + 新项加入最短列”为准。

让列数和间距支持响应式

这是标题中“响应式”的核心部分。文档确认columnsspacing都接受以断点为键的响应式对象。

对应 ResponsiveColumns.tsx:

<Masonry columns={{ xs: 3, sm: 4 }} spacing={2}> {heights.map((height, index) => ( <Item key={index} sx={{ height }}> {index + 1} </Item> ))} </Masonry>

在小屏幕(xs断点)下显示 3 列,sm断点及以上显示 4 列,其余代码与基础示例相同。

对应 ResponsiveSpacing.tsx:

<Masonry columns={3} spacing={{ xs: 1, sm: 2, md: 3 }}> {heights.map((height, index) => ( <Item key={index} sx={{ height }}> {index + 1} </Item> ))} </Masonry>

列数固定为 3,但间距随断点变化:xs下为theme.spacing(1)sm下为theme.spacing(2)md下为theme.spacing(3)

验证方式:拖动浏览器窗口跨越smmd断点,观察列数或间距是否按上面配置切换。官方文档中这两个示例均带有可交互演示(见 masonry.md 的 Columns 与 Spacing 两节)。

可选:改为从左到右的顺序排布

默认情况下 Masonry 始终把新元素加入最短列。如果业务上要求元素严格按书写顺序从左到右排布,可以给Masonry增加sequential属性。官方文档说明:启用sequential后,“items are added in order from left to right rather than adding to the shortest column”。

对应 Sequential.tsx:

<Masonry columns={4} spacing={2} defaultHeight={450} defaultColumns={4} defaultSpacing={1} sequential > {heights.map((height, index) => ( <Item key={index} sx={{ height }}> {index + 1} </Item> ))} </Masonry>

注意此示例同时设置了defaultHeightdefaultColumnsdefaultSpacing(SSR 相关,下一节解释),如果不需要 SSR 支持,只保留columnsspacingsequential即可。

SSR 场景:defaultHeight / defaultColumns / defaultSpacing

在水滴流这种依赖实际渲染高度计算位置的布局里,服务端渲染阶段拿不到元素真实高度。官方文档的 “Server-side rendering” 一节给出了对策:使用defaultHeightdefaultColumnsdefaultSpacing这三个属性来支持 SSR。

对应 SSRMasonry.tsx:

<Box sx={{ width: 500, minHeight: 393 }}> <Masonry columns={4} spacing={2} defaultHeight={450} defaultColumns={4} defaultSpacing={1} > {heights.map((height, index) => ( <Item key={index} sx={{ height }}> {index + 1} </Item> ))} </Masonry> </Box>

三个属性各自的作用,结合文档与源码 Masonry.js 可以明确:

  • defaultColumns:SSR 阶段按此列数把容器分成等宽列(源码中据此计算每列宽度和行分组),同时它是触发 SSR 模式的判断条件之一;
  • defaultHeight:SSR 阶段容器的占位高度。文档明确要求:defaultHeight应大到足以渲染所有行
  • defaultSpacing:SSR 阶段参与列间距计算的间距值。源码中与spacing一样会先经过theme.spacing换算(parseToNumber(theme.spacing(ownerState.defaultSpacing)))。

源码中的判断逻辑是:只有当defaultHeightdefaultColumnsdefaultSpacing三者提供时,组件才按 SSR 样式渲染(见 Masonry.js 中isSSR的判定);只设置其中一两个不会启用 SSR 样式。

SSR 场景的验证与限制(均来自官方文档):

  • 服务端渲染的 HTML 中,子项按defaultColumns列均分,容器高度为defaultHeight
  • 文档明确说明:在服务端渲染的情况下,元素不会被加入最短列——这是 SSR 结果与客户端布局的主要差异,首屏可能出现“客户端水合后布局再次调整”的现象,属于预期行为;
  • defaultHeight给得不够大,不足以容纳所有行,属于配置错误,需要调大该值。

defaultHeight={450}等具体数值是文档示例的取值,实际项目应根据自己的行数与列数重新估算,保证“足够渲染所有行”。

参考的官方示例与文档位置

内容路径
Masonry 文档(含全部示例入口)docs/data/material/components/masonry/masonry.md
基础瀑布流docs/data/material/components/masonry/BasicMasonry.tsx
响应式列数docs/data/material/components/masonry/ResponsiveColumns.tsx
响应式间距docs/data/material/components/masonry/ResponsiveSpacing.tsx
变高子项(如 Accordion)docs/data/material/components/masonry/MasonryWithVariableHeightItems.tsx
顺序排布docs/data/material/components/masonry/Sequential.tsx
SSR 示例docs/data/material/components/masonry/SSRMasonry.tsx
组件源码packages/mui-lab/src/Masonry/Masonry.js

两点边界补充:

  1. 文档中的 Image masonry 示例展示了用 Masonry 排布图片,其中图片按行排序;如果你的场景要求图片按列排序,文档建议改用 ImageList 组件的 masonry 模式(参见 docs/data/material/components/image-list/image-list.md)。
  2. 变高内容的另一种形态:子项不是固定像素高度而是可展开/折叠的组件(如 Accordion)时,可直接作为 Masonry 子项,Masonry 会依据实际高度在列间移动它们(见 MasonryWithVariableHeightItems.tsx),无需额外配置。

【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询