
本文详解如何使用 CSS Grid 的 grid-template-rows 配合 fr 单位和过渡动画,实现整行内容同步隐藏/显示的 collapsible 效果,避免子元素错位、分步消失等常见问题。
本文详解如何使用 css grid 的 `grid-template-rows` 配合 `fr` 单位和过渡动画,实现整行内容同步隐藏/显示的 collapsible 效果,避免子元素错位、分步消失等常见问题。
在构建动态数据表格或可交互信息面板时,常需对 Grid 布局中的某一行进行折叠(collapse)与展开(expand)操作。理想效果应是:整行作为一个视觉单元平滑收缩/伸展,所有列内容(图片、文本、SVG)同步进出,无错位、无残留、无分步闪烁。但直接对 .grid-row 使用 height: 0 或 opacity 过渡往往失效——因为 Grid 容器的高度由行轨道(grid-template-rows)控制,而非单个子项。
核心解决方案是:仅通过 grid-template-rows 的 0fr ↔ 1fr 切换驱动动画,并配合恰当的布局约束。
✅ 正确实现原理
-
0fr是关键:它表示“零份额的可用空间”,即该行轨道高度为 0,且支持 CSS 过渡(fr单位可动画化,而0px或auto不可)。 -
移除
align-items: center:该属性在grid-template-rows: 0fr时仍可能使内容溢出容器顶部或底部,导致视觉残留;折叠时应依赖overflow: hidden+min-height: 0确保裁剪。 -
子项无需独立动画:不再为每个
.grid-item设置transform或visibility过渡——它们会随父行轨道自然收缩,保持空间一致性。 -
垂直居中改用
vertical-align: middle:针对<img alt="如何实现 Grid 行的平滑折叠与展开动画" >和<svg></svg>等替换元素,在行高为 0 时也能稳定对齐,避免因基线对齐产生的额外空白。
? 示例代码(精简可靠版)
:root {
--transitionLength: 250ms;
--transitionTiming: ease-out;
}
.grid {
display: inline-grid;
grid-template-columns: 110px minmax(200px, max-content) 1fr;
row-gap: 5px;
}
.grid-row {
display: grid;
grid-column: 1 / 4; /* 跨越全部三列 */
grid-template-columns: subgrid;
background-color: lightgray;
grid-template-rows: 0fr; /* 初始折叠状态 */
transition: grid-template-rows var(--transitionLength) var(--transitionTiming);
column-gap: 10px;
}
.grid > .visible {
grid-template-rows: 1fr; /* 展开状态:占据全部可用空间 */
}
.grid-row > .grid-item {
overflow: hidden;
min-height: 0; /* 关键:防止内容撑开折叠行 */
}
.grid-item > img,
.grid-item > svg {
vertical-align: middle; /* 替代 align-items,更稳定 */
}<div class="grid">
<div class="grid-row visible">
<div class="grid-item img"><img src="https://picsum.photos/100" alt="Image"/></div>
<div class="grid-item label"><h2>Can be a long Line...</h2></div>
<div class="grid-item svg">
<svg width="163.63" height="100" viewBox="0 0 18 11">
<rect width="18" height="11" fill="#fff"/>
<path d="M0,5.5h18M6.5,0v11" stroke="#002F6C" stroke-width="3"/>
</svg>
</div>
</div>
<div class="grid-row">
<div class="grid-item img"><img src="https://picsum.photos/100" alt="Image"/></div>
<div class="grid-item label"><h2>...or very short</h2></div>
<div class="grid-item svg">/* same SVG */</div>
</div>
</div>
<input type="number" id="row" value="1" min="1" max="2"/>
<button onclick="toggleRow()">Toggle Row</button>function toggleRow() {
const i = d3.select('#row').property('value');
const row = d3.select('.grid-row:nth-child(' + i + ')');
row.classed('visible', !row.classed('visible'));
}⚠️ 注意事项与最佳实践
-
避免
align-items/justify-items:在折叠行上启用这些属性可能导致内容脱离轨道边界,即使grid-template-rows: 0fr也无法完全隐藏。 -
确保
min-height: 0作用于直接子项:.grid-row > .grid-item必须显式设置,否则浏览器可能按默认最小尺寸(如图片固有高度)渲染,破坏折叠效果。 -
慎用
visibility: hidden或opacity:它们不改变文档流,无法真正“收回”空间,会导致下方行位置不变,失去折叠意义。 -
响应式兼容性:
fr单位和subgrid在现代浏览器(Chrome 105+、Firefox 71+、Safari 16.4+)中已广泛支持;若需兼容旧版 Safari,可降级为max-height+overflow: hidden组合方案(但动画精度略低)。
此方法以语义清晰、代码简洁、性能优异著称——动画由浏览器原生 Grid 引擎驱动,无 JavaScript 布局强制刷新,适合高频交互场景。

















