纯 css grid 无法真正实现瀑布流,因 grid-template-rows 静态且列高强制对齐;当前最稳方案是 grid-auto-flow: column 结合 js 动态分配元素至最短列,并配合 resizeobserver、防抖及图片加载后重排等细节处理。

纯 CSS Grid 无法真正实现瀑布流,grid-template-rows 是静态的,所有列会被强制拉齐到同一高度;所谓“三行代码搞定”的 display: grid-lanes 目前仅存在于 Safari 技术预览版,未进标准,生产环境不可用。
为什么 grid-auto-flow: column + JS 是当前最稳方案
Grid 负责列宽、间距和断点,JS 只管把每个元素塞进当前最短列——逻辑清晰、兼容性好、能应对图片加载延迟和字体重排。
-
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr))定义列数,auto-fill保留空列占位,避免小屏初加载只出一列 -
grid-auto-flow: column让浏览器按列顺序排列(而非默认的按行),为 JS 重排打基础 - JS 不靠
order属性(易受 CSS 优先级干扰),直接用appendChild移动 DOM 节点,确保渲染顺序与视觉一致 - 每次插入后必须用
item.getBoundingClientRect().height更新列高,不能用offsetHeight(可能含边框/滚动条误差)
grid-auto-rows: minmax(100px, auto) 的真实作用
它不是用来“撑开行高”,而是防止极矮卡片塌陷,并给 Grid 渲染引擎一个最小轨道参考。别写成 auto 单独值,旧版 Chromium 会忽略;也别用 fit-content,它在 Grid 行方向不生效。
- 若内容含图片,必须加
img { display: block; width: 100%; height: auto; },否则vertical-align: baseline会在底部多出 4px 空白,导致列高计算失准 -
gap控制项间间距,别在 item 上写margin,否则会干扰 JS 对高度的测量 - 移动端需配
@media (max-width: 768px) { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); },否则小屏强行撑两列,每列窄得只剩图标
响应式重排时最容易漏掉的两件事
窗口缩放不仅改变列数,还会让已分配的节点顺序立刻失效。只监听 window.resize 不够,因为 resize 频率太高且不反映容器实际尺寸变化。
- 必须用
ResizeObserver监听容器宽度,而不是整个 window - 重排逻辑要防抖,比如
setTimeout(() => { redistributeItems() }, 100),等浏览器完成 layout 再执行,避免反复触发回流 - 懒加载图片完成后再触发一次重排,否则 JS 初始计算时高度为 0,后续图片加载会撑开列高却没更新其他列的分配状态
真正麻烦的从来不是怎么写第一版,而是图片加载异步、字体加载异步、用户缩放、SSR 首屏直出、键盘导航顺序这些叠加起来的细节——它们不会报错,但会让瀑布流在某个机型上突然错位或卡 tab 键。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











