transition必须写在基础class上,而非仅:hover或.entering中;可过渡属性仅限opacity、transform等支持插值的数值型属性;display和visibility不可过渡;单向动画需分离entering/leaving类;dom移除须监听transitionend事件并校验属性值。

transition必须写在初始状态,不能只写在:hover或.entering里
很多人以为给.box:hover加transition: transform 0.3s就能让鼠标移入移出都动,结果只有移入有动画、移出直接跳变。这是因为transition规则只存在于:hover中,移出时浏览器找不到过渡声明,只能硬切回默认值。
正确做法是把transition写在元素的**基础class**上,比如.box本身:
.box {
opacity: 0;
transform: translateY(10px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.box.show {
opacity: 1;
transform: translateY(0);
}
- transition写在
.box里,进和出都会触发——前提是进出都靠修改.show这个class - 如果用
:hover控制,也要确保基础状态有transition,hover里只改属性值,不重复写transition - 别用
transition: all 0.3s,它会把后续意外改动的padding、border-color也拖进动画,干扰预期
display: none和visibility: hidden都不能过渡
想用display: none配合transition实现淡出?不行。display是离散值(none / block / flex…),没有中间状态,transition根本无法插值。同理,visibility: hidden虽能切换,但它是布尔式开关,没有缓动,动画会卡顿或失效。
真正可过渡的属性只有那些支持数值插值的,比如:
-
opacity(0 → 1) -
transform(translateX(-20px) → translateX(0)) -
height(但必须是具体数值,height: auto无效) -
width、max-height(需固定起止值)
如果需要“隐藏后不占位”,得等opacity过渡结束再设display: none,不能靠CSS自动完成。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
单向动画:进入有过渡,离开立刻消失
有些场景(比如tooltip、toast)要求“进来慢慢显,走时立刻消失”,不能靠同一个transition来回控制。这时候要分离声明:
.tooltip {
opacity: 0;
transform: scale(0.95);
}
.tooltip.entering {
opacity: 1;
transform: scale(1);
transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}
.tooltip.leaving {
opacity: 0;
transform: scale(0.95);
/* 不写 transition —— 离开即刻生效 */
}
- JS控制逻辑:先加
.entering,监听transitionend后移除;离开时直接加.leaving并同步移除.entering - 关键点:
transition只出现在「要动的那一侧」,另一侧保持无声明或显式设为transition: none - 别在
.leaving里写transition-delay试图“延迟隐藏”——它只会延迟开始,不是延迟执行
清理DOM前必须监听transitionend,不能靠setTimeout
opacity降到0后,元素还在DOM里,仍占布局、响应事件、影响tab顺序。想真正移除,得等动画结束再调el.remove()。但硬写setTimeout(() => el.remove(), 300)不可靠——时长可能被重排打断、用户缩放页面会影响帧率、不同设备渲染速度不一。
应该监听原生事件:
el.addEventListener('transitionend', (e) => {
if (e.propertyName === 'opacity' && getComputedStyle(el).opacity === '0') {
el.remove();
}
});
- 必须过滤
e.propertyName,否则transform或height的过渡也会触发回调 - 必须检查当前
opacity值是否为'0',避免因多次快速切换导致误删 - 如果用了
will-change: transform,记得在remove前清除,防止渲染层残留
实际项目中最容易被忽略的是:transition的生效依赖两次样式计算之间存在重排间隔。用JS连续设置class再移除,浏览器可能合并操作,跳过过渡。必要时得用el.offsetHeight强制触发重排,才能让动画真正跑起来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










