浏览器不支持对grid-template-rows做transition,因其属不可动画的结构化轨道定义;真正可动画的是max-height或transform等可插值属性。

为什么grid-template-rows里写0fr → 1fr根本不动画
不是你语法错,是浏览器压根不支持对grid-template-rows做transition。这个属性值属于「结构化轨道定义」,比如"100px 1fr"或"0fr 2fr",它不是单一数值,而是描述整行分配逻辑的字符串。W3C 明确标注该属性为 not animatable——所有主流浏览器(Chrome/Firefox/Safari)都跳过过渡,直接重排布局。
常见错误现象包括:
• 写了transition: grid-template-rows 0.3s但毫无反应
• JS 动态改element.style.gridTemplateRows,尺寸“啪”一下切换
• 控制台无报错,动画就是不跑——纯属规范限制,非 bug
0fr看起来能动,其实是假象
有些代码看似生效,比如:
.accordion { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.25s; overflow: hidden; }
.accordion.open { grid-template-rows: 1fr; }
但它实际行为是:初始渲染时0fr让该行“分配 0 份剩余空间”,但内容仍在文档流中;展开时浏览器强制重排,1fr立刻占满可用高度——中间没有插值帧,只是视觉上“好像平滑”,尤其当内容少、父容器高度固定时容易误判。
真正起作用的从来不是fr,而是:
• 父容器overflow: hidden掩盖了重排跳变
• 内容本身高度小,重排耗时短,人眼难察觉
• 没对比就以为“有动画”,一加border或box-shadow立刻暴露跳变
真正能平滑过渡的高度控制方式
绕开grid-template-rows,转而控制子元素自身尺寸,靠max-height或transform实现可插值动画:
-
max-height必须设具体数值(如max-height: 400px),不能用none或fit-content,否则过渡失效 - 初始状态建议组合
max-height: 0+opacity: 0+overflow: hidden - 展开目标值要覆盖内容最大可能高度;若高度不确定,需用 JS 先调
getBoundingClientRect().height再写入 - 对网格项单独缩放,用
transform: scaleY()比动轨道更稳,且transition: transform 0.25s在所有现代浏览器中都可靠
为什么fr单位本身就不能被插值
fr不是长度单位,是「弹性份额」,它的实际像素值取决于容器剩余空间和其它轨道的尺寸。浏览器无法在0fr和1fr之间算出第 10 帧该是多少像素——因为那取决于此时父容器宽高、字体大小、甚至滚动条是否存在。这种依赖上下文的计算,天然无法线性插值。
这也是为什么:
• transition: grid-template-columns 0.3s同样无效
• calc(1fr + 20px)或minmax(0, 1fr)也救不了动画
• 所有试图用 JS 强刷style.gridTemplateRows的行为,都会触发 layout thrashing,卡顿且不可预测
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











