height: auto 不可动画,因浏览器无法计算中间帧;grid-template-rows 从 0fr 到 1fr 可实现丝滑动画,但需 display: grid、显式定义 grid-template-rows、子元素 grid-row 占位,并配合 overflow: hidden。

为什么直接用 height: 0 → height: auto 做不了丝滑动画
因为 height: auto 是不可动画的 CSS 属性值,浏览器无法计算中间帧,强行加 transition 会直接跳变或完全失效。很多人卡在这一步,转而用 JS 测高、设固定像素——既脆弱又难维护。
grid-template-rows 从 0fr 到 1fr 真的能动?怎么写才生效
能动,但有硬性前提:必须配合 display: grid + 显式定义 grid-template-rows,且子元素需用 grid-row 占位。关键不是“fr 单位”,而是浏览器能对 fr 值做线性插值(0fr 和 1fr 都是有效数值)。
实操要点:
- 父容器设
display: grid和grid-template-rows: 0fr(初始收起) - 面板内容元素必须显式声明
grid-row: 1,否则不参与该轨道布局 - 动画触发时,把
grid-template-rows改成1fr,并加transition: grid-template-rows 0.3s ease - 别忘了给内容区设
overflow: hidden,否则高度撑开时内容会溢出
示例片段:
立即学习“前端免费学习笔记(深入)”;
.accordion-panel {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.3s ease;
overflow: hidden;
}
.accordion-panel.is-open {
grid-template-rows: 1fr;
}
.accordion-panel > * {
grid-row: 1;
}用 0fr/1fr 的真实限制和替代方案
这个技巧看着巧妙,但实际有三个常被忽略的约束:
- 只适用于单行内容(或多行但高度可预测),因为
1fr是按可用空间等分,不是“刚好包住内容”——如果父容器高度受限,1fr可能比内容还小,导致截断 - 不能和
align-content或justify-items混用,容易干扰轨道计算 - IE 完全不支持
fr单位,哪怕加前缀也无效
更稳妥的替代路径:
- 用
max-height替代height(设一个足够大的安全值,如max-height: 500px),配合overflow: hidden - 需要精确控制时,用
getBoundingClientRect()测高后内联设置height,再过渡——虽然多一步,但行为确定
折叠时内容闪烁或抖动?检查这几个点
常见于内容含图片、字体加载未完成,或父容器没有稳定尺寸。根本原因是 grid-template-rows 动画依赖布局测量,而异步资源会让测量结果在动画中变化。
- 确保图片加
width/height属性,或用aspect-ratio占位 - 避免在面板内用
font-display: swap且未设 fallback 字体大小,FOUT 会导致重排 - 如果父容器宽度随展开变化(比如用了
fit-content),动画期间宽度抖动会连带影响高度表现 - 调试时临时加
outline: 1px solid red到面板容器,观察是否真正在缩放轨道,还是只是内容溢出造成错觉
真正丝滑不靠技巧多炫,而在于布局可控、测量稳定、边界明确。用 0fr/1fr 是个好切入点,但别让它掩盖了对盒模型和渲染流程的基本判断。


















