display 不支持 CSS 过渡,因其为离散属性无法插值;需用 opacity+visibility 组合实现渐变效果,并在 transitionend 中精准清理 display 和 aria-hidden 以保障布局与可访问性。

transition: display 0.3s 根本不会启动
浏览器压根不处理 display 的过渡——它不是卡顿,是直接丢弃规则。你在 DevTools 的 “Computed” 面板里搜不到这条 transition,因为它被渲染引擎静默过滤了。原因很简单:display 是离散属性(none、block、flex 等之间没有数值关系),无法插值,也就没有“50% 显示”这种中间帧可算。
display: none 会让子元素的 opacity 动画也失效
一旦父元素设了 display: none,它的所有子元素立刻脱离渲染树,样式计算和重绘全部暂停。哪怕子元素自己写了 transition: opacity 0.3s,也完全没机会执行。
- 常见现象:父容器切换时,子元素“啪”一下消失,连淡出都没有
- JS 同步写
el.style.display = 'block'; el.classList.add('fade-in'),浏览器会合并重绘,起始帧丢失 - 想强制触发?得用
el.offsetHeight这类 layout-trigger 打断优化,但慎用于高频场景
opacity + visibility 组合必须显式声明且错开时机
只写 opacity: 0,元素还挡点击;只写 visibility: hidden,又没渐变。二者必须协同,且 visibility 的切换时机必须卡在 opacity 动画结束那一帧,否则会闪、会误点、会焦点穿透。
- 初始态:
opacity: 0; visibility: hidden; - 过渡声明必须显式包含两者:
transition: opacity 0.3s ease, visibility 0s 0.3s;(visibility延迟生效) - 显示态:
opacity: 1; visibility: visible;,同时清除visibility的延迟:transition: opacity 0.3s ease, visibility 0s; - 别依赖
transition: all—— 它不会自动包含visibility
动画结束后不清理 display: none,布局和可访问性都会出问题
visibility + opacity 解决了动画,但元素还在文档流里占位。如果内容庞大、父容器有 overflow: hidden、或需要屏幕阅读器支持,就不得不补一刀 display: none。
- 监听
transitionend事件,只在event.propertyName === 'opacity'时执行清理 - 同步设置
element.style.display = 'none'和element.setAttribute('aria-hidden', 'true') - 记得移除
tabindex或 blur 当前焦点,否则键盘用户可能卡在不可见元素上 - 如果元素需彻底释放高度(比如收起的菜单),还得叠加
max-height: 0或transform: scaleY(0)配合overflow: hidden
真正容易被忽略的是:DOM 卸载时机与动画完成的错位。哪怕你把 CSS 写得再准,只要没在 transitionend 里检查 propertyName 并清理 display 和 aria-hidden,元素就一直占着布局、拖慢重排、干扰辅助技术。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











