Grid项hover展开时transform+transition不生效,因grid-template-rows/columns值离散不可插值,且grid-row/column非可动画属性;应改用内部容器的transform:scaleY()配合overflow:hidden和transform-origin实现无布局抖动的平滑过渡。

Grid 项 hover 展开时,为什么 transform + transition 不生效?
因为 grid-template-rows 或 grid-template-columns 的值是离散的(比如 "1fr 2fr"),无法被 CSS 动画插值。直接对 grid-row 或 grid-column 做 transition 也无效——它们不是可动画属性。
真正能平滑过渡的只有:尺寸(height、width)、位移(transform)、透明度(opacity)、缩放(scale)等支持插值的属性。
所以必须绕开 Grid 轨道定义本身,转而控制卡片内容容器的尺寸或视觉状态:
- 给每个 grid item 内部加一层
div包裹内容,设为overflow: hidden - hover 时用
height+transition控制展开,或更推荐用transform: scaleY()配合origin定向缩放 - 避免在
:hover中修改grid-area或grid-row,这会触发 layout,导致跳动
用 transform: scaleY() 实现无布局抖动的展开动画
相比 height 过渡,transform 不触发布局重排,性能更好,且能精准控制展开方向(比如从上向下“拉开”)。
立即学习“前端免费学习笔记(深入)”;
关键点在于设置 transform-origin 和初始缩放值:
- 卡片内部容器设
transform-origin: top,再设transform: scaleY(0)初始态 - hover 时设
transform: scaleY(1),并加transition: transform 0.3s ease-in-out - 必须同时设
overflow: hidden在父容器(grid item)上,否则缩放时内容会溢出 - 如果卡片有 border 或 padding,需额外处理:把 border 移到内部容器上,或用
box-sizing: border-box保持尺寸稳定
article {
overflow: hidden;
}
article > div {
transform-origin: top;
transform: scaleY(0);
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
article:hover > div {
transform: scaleY(1);
}
Grid 自适应与展开后其他项的位置偏移问题
Grid 默认是静态轨道,当某个 item 内容区域高度突变,它不会自动“推”开相邻项——除非你用了 grid-auto-rows: minmax(min-content, max-content) 或显式设了 auto 行高。
但即便如此,hover 展开仍可能造成下方项“上跳”或闪烁,原因常是:
- 没给 grid container 设
grid-auto-flow: row(默认就是,但显式写上更稳妥) - item 没设
min-height或height,导致未 hover 时高度塌缩(尤其含图片/异步内容时) - 展开容器用了
height: auto,但 transition 不支持auto→ 必须用max-height替代(配合足够大的数值,如max-height: 500px),或坚持用transform避开尺寸计算
最稳方案仍是 transform + overflow: hidden,不依赖 Grid 行高重算。
移动端 touch 设备下 hover 不触发怎么办?
手机和平板没有持续 hover 状态,:hover 伪类只在点击瞬间触发,导致动画一闪即逝。
解决思路不是模拟 hover,而是改用 class 控制状态:
- 用 JavaScript 监听
click(或touchstart),给目标 item 添加is-expanded类 - CSS 把
article:hover > div改成article.is-expanded > div - 注意:iOS Safari 对
transform+transition在position: absolute元素上有渲染 bug,建议展开容器用position: relative - 别忘了加
@media (hover: hover) and (pointer: fine)条件,桌面端保留 hover,触屏端走 JS
复杂点在于状态管理——比如点击一个卡片展开,是否要收起其他已展开的?这个逻辑得自己补。


















