如何让 CSS Grid 的高度只由第一列决定,并保持第二列卡片等高?
可以继续使用绝对定位,在滚动容器内增加一层 Grid:外层 .wrapper 限制可见高度并负责滚动,内层 .cards 使用自动高度和 grid-auto-rows: 1fr,让卡片等高。
第一列决定外层 Grid 的高度,第二列的卡片则可以在滚动区域内向下展开。
为什么原来的卡片没有保持等高?
原始结构中,第二列的内容参与外层 Grid 的行高计算,长列表会把整行撑高。
改用绝对定位后,长列表不再撑高外层 Grid,但 .wrapper 同时具有 height: 100% 和 display: grid,卡片网格的高度因此受到限制。
1fr 单独作为轨道尺寸时相当于 minmax(auto, 1fr)。高度受限、内容放不下时,各行内容的最小尺寸可能不同,因此不能保证所有行等高。高度自动、可用高度不确定时,Grid 会根据内容计算共同的 fr 尺寸。这里每张卡片各占一行,每行都是 1fr,可以得到等高的行。相关计算规则见 CSS Grid 规范。
修改 HTML:增加卡片网格层
在第二个示例的 .wrapper 内增加 .cards,把原来的所有 .card 移进去。下面展示前两张卡片,其余卡片按相同方式保留:
<div class="app">
<div class="first">
<div class="resizable">This is resizable.</div>
</div>
<div class="second">
<div class="wrapper">
<div class="cards">
<div class="card">
<div class="name">Zog Blorpton</div>
<div class="job-title">
Chief Button Alignment Officer, Button Engineering
</div>
</div>
<div class="card">
<div class="name">Luma Sparklefizz</div>
<div class="job-title">
Senior Unicorn Logistics Manager, Mythical Operations
</div>
</div>
<!-- 其余 .card 放在这里 -->
</div>
</div>
</div>
</div>
替换布局 CSS
用下面的规则替换原有布局规则,原来的 .card、.name 和 .job-title 样式可以保留:
* {
box-sizing: border-box;
}
.app {
display: grid;
grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
align-items: stretch;
gap: 0.5em;
width: 700px;
}
.first {
height: 300px;
resize: vertical;
overflow: auto;
background: lightgray;
}
.second {
position: relative;
min-width: 0;
min-height: 0;
}
.wrapper {
position: absolute;
inset: 0;
overflow: auto;
background: lightgray;
}
.cards {
display: grid;
grid-template-columns: minmax(0, 1fr);
grid-auto-rows: 1fr;
gap: 0.5em;
height: auto;
min-height: 100%;
padding: 0.5em;
}
需要完整替换旧的 .wrapper 规则,把原来的 display: grid、grid-auto-rows、gap 和 padding 移到 .cards,避免旧规则继续影响布局。
.wrapper 通过 inset: 0 填满第二列。它脱离正常流,内部列表不会再为外层 Grid 提供内容高度。绝对定位元素不参与 Grid 轨道尺寸计算的规则见 CSS Grid 中的绝对定位。
.cards 保持 height: auto,让等高行按内容展开;min-height: 100% 则让卡片较少时仍能填满滚动区域。卡片较多时,内层网格可以超过这个最小高度,由 .wrapper 显示滚动条。
使用时注意什么?
- 保留
.cards的自动高度,不要给它添加height: 100%或固定的max-height,否则会再次限制卡片网格的可用高度。 minmax(0, 1fr)用于行高时,允许行收缩到内容放不下的高度,可能导致文字溢出;这里的卡片行继续使用1fr。- 示例中的
300px是第一列的初始高度,来自原问题的第二个示例。拖动.first的调整手柄后,第二列的滚动区域会随整行高度变化。 - 原代码中设置了
resize: vertical的元素是.first;.resizable只是它里面的普通子元素。 - 如果不需要卡片较少时填满右侧高度,可以删除
.cards的min-height: 100%,保留按内容计算的等高行。
备注:内容仅供参考。
