transition 不能直接作用于 display 切换,因 display 不可过渡且会立即移除元素;应改用 opacity、transform、height 配合 overflow: hidden 和 transitionend 事件实现平滑增删动画。

transition 不能直接作用于 display: none / flex 的切换
很多人试图给 .item 加 transition: all 0.3s,再用 JavaScript 切换 display: none 和 display: flex 来实现增删动画——这行不通。因为 display 是一个不可过渡的属性,浏览器遇到 display: none 会立即从渲染树中移除元素,transition 根本没机会触发。
用 opacity + transform + height 配合 overflow 实现“视觉删除”
真正可落地的做法是:不删 DOM,只隐藏视觉;等动画结束再真实移除。关键点在于:
- 初始状态设为
opacity: 1; transform: translateY(0); height: auto;,同时overflow: hidden; - 删除前添加临时类(如
.removing),设为opacity: 0; transform: translateY(-10px); height: 0; - 必须显式设置
transition: opacity 0.3s, transform 0.3s, height 0.3s;—— 不能只写all,否则height: auto → 0无法计算时长 - 监听
transitionend事件,在height或opacity过渡完成后,再调用removeChild()或el.remove()
示例片段:
.item {
opacity: 1;
transform: translateY(0);
height: auto;
overflow: hidden;
transition: opacity 0.3s, transform 0.3s, height 0.3s;
}
.item.removing {
opacity: 0;
transform: translateY(-10px);
height: 0;
}
新增节点要避免“闪一下”:用 reflow 触发 + 动画反向播放
直接 appendChild() 后加类名,常导致新元素先以最终态渲染一帧再回退动画(即“闪”)。解决方法是强制一次同步 layout 计算:
立即学习“前端免费学习笔记(深入)”;
- 先插入节点,但不加动画类
- 立即读取一个布局属性(如
el.offsetHeight),强制 reflow - 再添加动画类(如
.entering),此时浏览器会从初始态开始过渡
对应的 CSS 可这样写:
.item.entering {
opacity: 0;
transform: translateY(20px);
}
.item.entering.active {
opacity: 1;
transform: translateY(0);
transition: opacity 0.3s, transform 0.3s;
}
Flex 容器本身需保持稳定,避免 justify-content / align-items 干扰动画
如果父容器用了 justify-content: center 或 flex-wrap: wrap,子项高度/透明度变化可能引发整行重排,导致其他项跳动。稳妥做法是:
- 对动态项统一设
flex-shrink: 0,防止被压缩 - 避免在动画过程中修改
flex-direction或flex-wrap - 若需多列布局,用
gap替代margin,它不会触发重排
最易被忽略的一点:所有参与过渡的尺寸值(height、margin、padding)必须是确定值或 0,auto 在过渡中几乎不可控,尤其是 flex 子项的 height: auto 与 overflow: hidden 组合时,浏览器行为在 Safari 和 Chrome 中也不完全一致。


















