结论:用 opacity + transition 控制显隐,配合 visibility 或 dom 移除收尾,别碰 display: none——它不支持过渡,硬加 transition 也无效。

直接给结论:用 opacity + transition 控制显隐,配合 visibility 或 DOM 移除收尾,别碰 display: none —— 它不支持过渡,硬加 transition 也无效。
为什么不能用 display: none / block 做淡入淡出
CSS transition 只对「有中间值」的属性生效,比如 opacity(0→1)、width(100px→200px)。而 display 是离散值:none 和 block 之间没有“0.5个 block”这种状态,浏览器无法插值计算,所以动画直接跳变。
常见错误现象:
- 写了
transition: all 0.3s,但模态框仍是瞬间出现/消失 - 加了
display: none后再 JS 切成block,结果 opacity 动画根本没触发
正确写法:opacity + transition 必须在初始 class 里声明
过渡声明必须存在于元素首次渲染时的 class 中,不能等 JS 切换状态时才加上。否则浏览器不会监听 opacity 变化。
Tailwind 示例(推荐):
div className={`fixed inset-0 bg-black/50 flex items-center justify-center transition-opacity duration-300 ${isVisible ? 'opacity-100' : 'opacity-0'}`}
原生 CSS 示例:
.modal { opacity: 0; transition: opacity 0.3s ease; } .modal.show { opacity: 1; }
关键点:
-
transition必须写在默认状态(非:hover、非.show),否则回退动画失效 - 别用
transition-all替代,它会把后续所有样式变更(如padding、transform)都套上过渡,干扰预期效果 -
opacity: 0的元素仍占布局空间、能响应点击和 tab 导航,不是真正“隐藏”
如何真正移除模态框,而不是只变透明
仅靠 opacity: 0 不等于释放 DOM 占位或禁用交互。你得等动画结束再清理:
- 监听
transitionend事件,且只响应opacity属性变化:if (e.propertyName === 'opacity') - 检查当前 computed opacity 是否为
'0',避免 height 或 transform 的过渡误触发 - 确认后调用
el.remove()或设visibility: hidden(注意:visibility本身不可过渡,只能当兜底) - 错误做法:用
setTimeout(() => el.remove(), 300)—— 时长硬编码易错,重排或主线程阻塞会导致偏差
进阶:需要同时控制占位与交互?加 max-height + overflow
如果模态框关闭后必须彻底退出文档流(比如防止背后内容被点击),单靠 opacity 不够。可组合 max-height + overflow: hidden:
.modal { opacity: 0; max-height: 0; overflow: hidden; transition: opacity 0.3s ease, max-height 0.3s ease; } .modal.show { opacity: 1; max-height: 600px; }
注意:
-
max-height必须设具体值(不能用auto),否则无过渡效果 - 这个方案适合高度相对固定的模态框;高度动态时建议用
height: 0+getBoundingClientRect()预测量,但复杂度陡增 - 别混用
visibility: hidden和transition-opacity:前者立即生效,会直接掐断 opacity 动画
最常被忽略的一点:动画结束后是否真把元素从 DOM 移除了?还是只留着一个 opacity: 0 的“幽灵节点”——它既影响性能,又可能意外接收焦点或事件。务必用 transitionend 精准判断,而不是凭感觉删。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











