grid-template-rows 不能加 transition 实现高度动画,因 CSS 规范明确禁止对其插值;可用 0fr→1fr 配合 overflow: hidden 或 max-height 过渡替代。

grid-template-rows 本身不能直接加 transition 实现高度动画——这不是你写错了,是 CSS 规范明确禁止对它做过渡。所有看似“写了但没反应”的情况,根源都在这里。
为什么 grid-template-rows 加 transition 完全无效
浏览器不支持对 grid-template-rows 做插值计算,因为它的值是结构化轨道定义(如 "0fr 1fr auto"),不是单一数值。即使你写成 "0fr" → "1fr",中间也没有可计算的像素帧;换成 "0px" → "200px" 同样无效——该属性在 CSS Transitions §2.1 中被列为 not animatable。
- 常见错误现象:
transition: grid-template-rows 0.3s写了,class 一换,内容瞬间展开/收起,毫无缓动 - Chrome 115+ 起可通过
@property+calc()绕过,但需显式注册变量、限定单位、且兼容性有限(Safari/FF 不支持) -
grid-row-start/grid-row-end可以过渡,但只移动位置,不改变轨道尺寸——和你要的“高度伸缩”不是一回事
真正能用的纯 CSS 方案:用 0fr → 1fr 配合 overflow: hidden
虽然 grid-template-rows 不能动画,但浏览器对 fr 单位在特定约束下有隐式插值行为:当整行定义从 0fr 切换到 1fr,且容器设了 overflow: hidden,就能触发平滑过渡。
- 父容器必须是
display: grid,且只定义单行承载目标内容,例如:grid-template-rows: 0fr(不能是auto或minmax()) - 切换时改为
grid-template-rows: 1fr,并确保内容区域没有 padding/margin 撑开导致溢出 -
overflow: hidden必须加在父容器上,否则0fr行仍可能显示内容(尤其含绝对定位或浮动子元素时) - 内容极少时
1fr可能收缩过度,建议改用minmax(0, max-content)替代1fr,但注意初始态仍得是0fr才能触发插值
更稳妥的方案:用 max-height 控制子项,Grid 结构保持不动
放弃驱动轨道变化,转而控制内容容器自身高度。这是目前兼容性最好、行为最可控的方式。
- 给要展开的内容包一层
<div class="expandable">,它作为 Grid 的一个子项,固定占某一行(如grid-row: 2) -
.expandable设overflow: hidden和transition: max-height 0.3s ease,初始max-height: 0,展开时设为足够大的具体值(如max-height: 500px) -
max-height不能用none或fit-content,否则过渡失效;若内容高度不可预估,可用 JS 先读scrollHeight再赋值 - Grid 容器自身保持固定行定义(如
grid-template-rows: 100px auto),不随展开状态变更,避免布局重排干扰
容易被忽略的关键点
很多人卡在最后一环:内容含图片或异步加载时,max-content 或 scrollHeight 测量时机不对,导致高度算小、文字截断或动画中断。
立即学习“前端免费学习笔记(深入)”;
- 如果内容里有
<img>,务必等img.onload后再切展开 class,或用requestAnimationFrame延迟一次渲染再测高 -
grid-template-rows: 0fr下,若子项用了display: flex但没设高度来源,flex 容器内部高度可能塌陷,需加min-height: min-content强制撑开 - 不要依赖
height: 100%在 Grid 子项中生效——Grid 容器若为height: auto,100% 就失去参照物


















