transition对height: auto无效,因auto非可插值数值,浏览器无法计算中间帧;可用max-height模拟、JS测高或grid-template-rows的0fr→1fr过渡实现伪动画。

为什么 transition 对 height: auto 无效
因为浏览器无法在动画起始帧和结束帧之间插值计算——auto 不是一个具体数值,transition 只能对可计算的长度单位(如 px、em、rem)做线性过渡。即使你写了 transition: height 0.3s,只要目标是 height: auto,动画就只会“跳变”。
常见错误写法:
.box {
height: 0;
overflow: hidden;
transition: height 0.3s;
}
.box.open {
height: auto; /* ❌ 这里不触发过渡 */
}- 改用
max-height模拟(需预估上限值,不灵活) - 用 JS 测量真实高度再设为具体像素(侵入性强、易出竞态)
- 换布局模型,绕过高度控制本身 —— 这正是
grid+fr的价值所在
用 grid 的 fr 单位替代高度控制
核心思路:不操作 height,而是通过 grid-template-rows 控制某一行的展开/收起状态,利用 fr 单位的弹性特性配合 transition 实现平滑过渡。
适用前提:容器是 display: grid,且需要展开的内容位于单独的 grid-row 中。
立即学习“前端免费学习笔记(深入)”;
.accordion {
display: grid;
grid-template-rows: auto 0fr; /* 第二行默认为 0fr(视觉上隐藏) */
transition: grid-template-rows 0.3s ease;
}
.accordion.open {
grid-template-rows: auto 1fr; /* 展开后占剩余空间 */
}-
0fr是合法值,表示该行不占用任何可用空间(不是0px,所以内容不会被截断,但因无空间而不可见) -
transition能对fr值插值,是因为它本质是比例系数,浏览器可线性过渡 0 → 1 - 必须搭配
overflow: hidden在父容器上,否则内容可能溢出 - 如果有多行要控制,用
grid-template-rows: auto 0fr auto等方式分隔,只对目标行设fr
兼容性与实际限制
fr 单位的过渡在 Chrome 89+、Firefox 75+、Safari 14.1+ 中稳定支持;IE 完全不支持,Edge 旧版(≤18)也不支持。
- 不能用于内联元素或
display: inline-grid的过渡(动画会失效) - 若子元素有
margin或padding,可能影响视觉节奏,建议统一用gap控制间距 -
0fr下子元素的height、min-height仍生效,但因父行无空间,内容会被裁剪 —— 所以务必加overflow: hidden - 若需“完全收起不留空隙”,第二行用
grid-template-rows: auto切换,但这样就失去过渡;折中方案是设0.01fr并配min-height: 0
和 JavaScript 配合时的关键点
纯 CSS 方案依赖类名切换,JS 只需负责添加/移除 .open 类,无需测量高度或操作 style.height。
但要注意:
- 避免在
click回调里连续多次el.classList.toggle('open'),可能触发过渡中断;推荐用el.classList.replace('open', 'closed')显式控制 - 若内容动态加载,确保 DOM 渲染完成后再加类(例如
await el.updateComplete或requestAnimationFrame) - 监听
transitionend事件时,检查event.propertyName === 'grid-template-rows',避免误响应其他过渡
真正难的不是写对这三行 CSS,而是想清楚:你到底是在控制“高度”,还是在控制“可见区域的分配权”。后者才是 grid + fr 解法成立的前提。


















