如何使用 CSS Grid 实现 Flex 包裹后子项自适应高度分配

当 flex 容器在小屏下换行时,无法自然实现“一个子项收缩至内容高度、另一个占满剩余空间”的布局;css grid 的 `grid-auto-rows: 1fr` 配合响应式列定义可优雅解决该问题。

在响应式英雄区(hero section)开发中,常见需求

是:宽屏下左右两栏并排(如图文+装饰区块),窄屏下自动换行为上下堆叠;但默认 Flex 换行后,所有子项会均分容器高度(因 flex-wrap 下 align-content 仅控制行间距,不改变单行内项目的高度分配),导致内容精简的区块被无谓拉伸,而内容丰富的区块又无法撑满可用空间。

此时,CSS Grid 是比 Flexbox 更合适的技术选型——它原生支持“首行自适应、后续行均分剩余空间”的行为,无需媒体查询即可实现目标效果。

核心方案如下:

  • 使用 display: grid 替代 display: flex
  • grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 40%)) 实现响应式列数:最小列宽 300px,最大占比 40%,屏幕足够宽时最多显示两列(auto-fit 自动填充空列)
  • grid-template-rows: auto 确保第一行(即首项所在行)高度由内容决定
  • grid-auto-rows: 1fr 关键!当发生换行(即生成第二行)时,该行将占据父容器剩余所有高度(等价于 flex: 1 在垂直方向的效果)
.hero {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 40%)));
  grid-template-rows: auto;
  grid-auto-rows: 1fr;
  height: 500px;
}

/* 装饰性样式(保持不变) */
.hero {
  background-color: hsla(0, 100%, 50%, 0.5);
  padding: 10px;
  border: 2px dotted red;
}
.item1 {
  background-color: hsla(120, 100%, 50%, 0.5);
  padding: 10px;
  border: 2px dotted green;
}
.item2 {
  background-color: hsla(240, 100%, 50%, 0.5);
  padding: 10px;
  border: 2px dotted blue;
}
Item1. Should be short when wrapped Item2. Should take all available height when wrapped.

优势总结

  • 无需 JavaScript 或媒体查询,纯 CSS 响应式;
  • grid-auto-rows: 1fr 精准控制换行后第二行的高度分配,避免 flex 下的溢出或高度塌陷问题;
  • minmax(min(300px, 100%), 40%) 兼容移动端(最小宽度取 min(300px, 100%) 防止超宽)与桌面端(上限 40% 保证双栏合理比例)。

⚠️ 注意事项

  • 确保 .item 元素不设置 height: 100% 或 min-height: 100%,否则会干扰 auto 行高的自然计算;
  • 若需三栏以上响应,可调整 minmax() 第二参数(如 30%),Grid 会自动按需生成列数;
  • 浏览器兼容性良好(Chrome 57+/Firefox 52+/Safari 10.1+),现代项目可放心采用。