纯 CSS Grid 可实现 Pinterest 式瀑布流,需绕过 Bootstrap 的 .row/.col 逻辑,用 grid-template-columns + grid-auto-rows + 动态 grid-row-end 控制列数与跨行,配合 ResizeObserver 和图片加载完成后的高度测量确保精度。

纯 Bootstrap 的 .row + .col 无法实现真正不规则瀑布流——它只是等宽分列,高度不一时必然留白。要达成 Pinterest 那种紧凑错落效果,必须绕过 Bootstrap 栅格逻辑,用 CSS Grid 主导布局,仅把 Bootstrap 当作工具链(如排版、间距、响应式断点辅助)来用。
为什么不能直接在 .row 上加 display: grid
Bootstrap 5+ 的 .row 默认是 display: flex,且带 flex-wrap: wrap 和负 margin;强行覆盖为 grid 会破坏其子项(.col)的宽度计算逻辑,导致列宽坍缩或溢出。更关键的是:.col 类自带 flex-basis、max-width 等声明,与 Grid 的列轨道控制冲突。
- 现象:设了
grid-template-columns: repeat(3, 1fr),但子项仍按col-4宽度挤在一列里 - 根本原因:
.col-4的flex: 0 0 auto+width: 33.333%优先级高于 Grid 的隐式轨道分配 - 解法:子项必须移除所有
.col-*类,改用语义化 class(如.grid-item),由 Grid 完全接管尺寸
grid-template-columns 该用 repeat(3, 1fr) 还是 auto-fill?
取决于你是否需要响应式列数变化。repeat(3, 1fr) 固定三列,适合内容量稳定、设计稿明确的场景;auto-fill 更灵活,但需配合 minmax() 避免列过窄。
- 固定列数(推荐初试):
grid-template-columns: repeat(3, 1fr)—— 简单可控,JS 计算跨行数时基准统一 - 响应式列数:
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr))—— 注意minmax()第一个参数不能太小,否则小屏下会生成极窄列 - 别用
auto-fit:它会收缩空列,导致最后一行 item 被拉宽,破坏瀑布流密度
如何让每个 .item 跨越正确行数?
CSS Grid 本身不读取内容高度,grid-row-end: span N 的 N 必须由 JS 动态计算。核心是用 grid-auto-rows: 10px 设定行高基准,再用元素实际高度除以它取整。
立即学习“前端免费学习笔记(深入)”;
- 先设父容器:
grid-auto-rows: 10px(别用1px,太小会导致浮点误差放大) - JS 中获取每个
.item的offsetHeight,然后Math.ceil(item.offsetHeight / 10) - 写入内联样式:
item.style.gridRowEnd = `span ${spanCount}` - 注意时机:必须等图片加载完成后再计算,否则高度为 0 —— 用
imagesLoaded或Promise.all(itemImages.map(img => img.decode()))
兼容性与容易被忽略的细节
Chrome/Firefox/Edge 均已稳定支持 grid-auto-flow: dense 和动态 grid-row-end,但 Safari 在 iOS 16.4 之前对 dense 模式有渲染抖动。真正的难点不在语法,而在高度测量精度和响应式重排。
- 不要依赖
clientHeight:它不含 padding 和 border,offsetHeight更准 - 窗口 resize 后必须重新计算所有 item 的跨行数,不能只监听
resize,要用ResizeObserver监听容器宽度变化 - Bootstrap 的
gap类(如gap-3)和 Grid 的gap会叠加,建议禁用所有 Bootstrap 间距类,用grid-gap统一控制


















