为何使用grid-template-rows实现高度动画需内层overflow:hidden?
我通过JavaScript给最外层元素添加/移除.grid-wrapper-hidden类,切换grid-template-rows在1fr与0fr之间,实现了元素高度的平滑过渡动画。但我搞不懂:为什么必须设置带有overflow:hidden的.grid-wrapper-inner内层元素?哪怕给最外层加overflow:hidden甚至min-height:0,删掉这个内层元素后动画还是不生效,想知道背后的原理。
代码示例
HTML代码
<div id="hidable" class="grid-wrapper"> <div class="grid-wrapper-inner"> <div class="content"> Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla Lorem ipsum bla bla bla </div> </div> </div> <button> Toggle </button>
CSS代码
.grid-wrapper { display: grid; grid-template-rows: 1fr; width: max-content; transition: grid-template-rows 300ms; border: 1px solid black; &-inner { overflow: hidden; } &-hidden { grid-template-rows: 0fr; } } .content { width: 200px; border: 1px solid red; }
原理解释
这核心是Grid布局中fr单位的计算逻辑和内容溢出约束的问题,拆解开说:
1fr/0fr的本质是「可用空间分配」
当你给.grid-wrapper设置grid-template-rows:1fr时,1fr代表「占据容器所有可用的行空间」;切换到0fr时,理论上该行的高度应该被压缩到0,但Grid行的高度默认会被**内部内容的最小高度(min-height:auto)**撑开,不会真的变成0。直接给外层加overflow:hidden无效的原因
没有内层.grid-wrapper-inner时,.content直接作为Grid子元素存在。Grid布局中,子元素的min-height:auto是优先级极高的规则——哪怕你给Grid容器加overflow:hidden,Grid行还是会优先满足子元素的最小高度需求,导致0fr无法真正把行高压缩到0,自然没有过渡动画的数值变化空间。内层overflow:hidden的关键作用
加了.grid-wrapper-inner后,它成为Grid的直接子元素,.content变成它的子元素:- 当Grid行被设置为
0fr时,Grid会强制把.grid-wrapper-inner的高度压缩到0; - 而
.grid-wrapper-inner的overflow:hidden会打破自身的min-height:auto约束——它不会被内部.content的高度撑开,而是严格遵守Grid行分配的高度; - 这样从
1fr(对应内容高度)到0fr(高度为0)的过渡就有了明确的数值变化,动画才能正常触发。
- 当Grid行被设置为
简单总结:这个内层元素是用来「承接Grid的行高约束」,同时用overflow:hidden切断内部内容对Grid行高的强制撑开,让fr单位的数值变化能真正体现在容器高度上,从而实现平滑过渡。
内容的提问来源于stack exchange,提问作者Furman

