纯 css grid 无法实现真正意义上的不定高瀑布流,因其 grid-auto-flow: dense 仅补漏不重排,且 grid-template-columns 不控列高;必须用 js 计算跨行数、监听容器 resizeobserver、处理图片字体加载及列高数组重置。

纯 CSS Grid 无法实现真正意义上的不定高瀑布流——它不自动把元素塞进最短列,grid-auto-flow: dense 只填空,不重排;grid-template-columns: repeat(auto-fill, ...) 只管列数,不管列高。必须配合 JS 才能落地。
为什么 grid-auto-flow: dense 不是解法
它只在已有轨道里“补漏”,不会动态拉伸列、也不会移动已定位的项。比如你设了 grid-row-end: span 5,浏览器就按这个位置放,哪怕左边一列只剩 20px 高,它也不会把下一项塞过去。现象是顶部留白、错位、看起来像“卡住了”。删掉它反而更可控,靠 JS 主动分配更稳。
用 grid-auto-rows + JS 计算跨行数
核心是把行高设成小而稳定的基准单位,让 JS 能可靠换算:
-
grid-auto-rows: 10px是较稳妥的起点(别用1px,浮点误差放大;也别用auto,旧 Chromium 会塌陷) - JS 中用
el.getBoundingClientRect().height获取真实渲染高度(比offsetHeight更准,避开渲染抖动) - 计算:
Math.ceil(height / 10)得到应跨行数,再写入el.style.gridRowEnd = `span ${spanCount}` - 必须等图片加载完成后再算——监听
img.onload或用img.decode()Promise
响应式重排必须监听容器宽度,不是窗口
列数变化取决于容器实际宽度,不是视口大小。常见错误是只监听 window.resize,结果容器被父级 flex 压缩后列数没变,但 JS 还按旧列数分配,导致错位。
- 用
ResizeObserver监听 Grid 容器本身 - 触发后用
requestAnimationFrame延迟执行重排,等布局稳定再读高度 - 小屏需降
minmax()第一个参数:比如从280px改为160px,否则列太窄、内容挤成图标 - 同步调小
gap,避免间距吃掉有效宽度
图片和字体导致的“歪了”最容易被忽略
这三件事不报错,但会让瀑布流视觉错乱:
-
<img>默认vertical-align: baseline,底部多出 4px 空白 → 必须加vertical-align: top或display: block - 字体加载晚或回流(如 Web Font 加载中)会导致卡片高度突变 → 重排逻辑得在
font-loaded后再跑一次 - 列高记录数组没清空或没重置 → 每次重排前要重新初始化
columns = Array(numCols).fill(0)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











