display: none 使 transition 失效,因 display 无法插值;应改用 opacity + visibility 组合,并配 step-end,动画结束后用 JS 添加 display: none。

display: none 会让 transition 完全失效,不是“动画卡住”,而是浏览器压根不启动过渡逻辑。
transition: display 0.3s 根本不会生效
浏览器只对可计算中间值的属性做过渡,比如 opacity、transform、width。而 display 是离散枚举值(none / block / flex…),没有“半显示”这种状态,所以无法插值。你写了 transition: display 0.3s,DevTools 的 computed 面板里都找不到这条规则——它被浏览器静默丢弃了。
常见错误现象:
- 元素“啪”一下消失,没淡出效果
- 用 JS 切换 class 后,opacity 动画也失效(因为
display: none把整个渲染树节点干掉了) - 父容器设了
overflow: hidden,visibility: hidden还占位,但display: none一上,兄弟元素立刻跳位
opacity + visibility 是最轻量可靠的组合
分工明确:opacity 控制视觉渐变,visibility 控制交互与布局占位。两者必须同时进 transition 声明,否则会闪或穿透:
- 只用
opacity: 0:元素不可见但仍挡点击、抢焦点 - 只用
visibility: hidden:无过渡,直接消失 - 正确写法:
transition: opacity 0.3s ease, visibility 0.3s step-end
step-end 是关键——它让 visibility 的切换严格卡在 opacity 动画最后一帧,避免 opacity 还没到 1 就突然可点。
需要真正释放空间时,得靠 JS 补一刀
visibility + opacity 解决了动画,但元素还在文档流里占位。如果要收起高度、腾出滚动空间、或配合 aria-hidden 做可访问性,就得在动画结束后手动加 display: none:
- 监听
transitionend事件,检查propertyName === 'opacity' - 回调里设
element.style.display = 'none',并同步更新aria-hidden="true" - 注意:父容器有
overflow: hidden时,visibility: hidden仍可能撑开滚动条,这时必须 JS 清除
折叠面板类场景,max-height 是更稳妥的 height 替代方案
想实现“收起高度”的动画(比如 FAQ 折叠),别碰 height: auto —— 它无法过渡。可行路径只有:
- 给元素设固定
height(不灵活) - 用
max-height模拟:初始设大值(如max-height: 500px),隐藏时设max-height: 0,再配overflow: hidden - 若内容高度差异大,
max-height的过渡时间会不准,此时得回退到 JS 测高 +height过渡
真正容易被忽略的是:所有这些方案都依赖“元素始终在渲染树中”。一旦你 JS 里先写 el.style.display = 'block' 再写 el.style.transform = 'scale(1)',浏览器大概率合并渲染,动画还是失效——这时候就得用 setTimeout 插个 16ms 延迟,把两步拆开。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











