CSS transition 对 display 无效,因其为离散属性无中间状态;应改用 opacity 与 visibility 组合动画,并监听 transitionend 事件控制 DOM 卸载。

为什么直接给 display 切换加 transition 没用
因为 display: none 和 display: block 是离散状态,CSS 无法对它们做过渡动画。你写 transition: display 0.3s ease 完全无效——浏览器直接跳变,没有平滑过程。
解决思路是:避开 display,改用可动画的属性,比如 max-height、opacity、transform 或 visibility 配合 height(但需固定高度)。最常用且兼容性好的组合是 max-height + overflow: hidden。
-
max-height设为一个「足够大但不过分夸张」的值,比如max-height: 300px(比下拉项总高略大) - 初始状态设
max-height: 0,同时加overflow: hidden隐藏溢出内容 -
:hover时改为max-height: 300px,配合transition: max-height 0.3s ease-in-out - 注意子菜单项的
padding、line-height会影响实际高度,预留余量
如何让下拉项真正「从上往下展开」而不是上下同时拉伸
单纯靠 max-height 过渡,默认是上下对称拉伸(因为元素默认居中或按 content-box 布局),视觉上像「撑开」而非「下拉」。要模拟真实下拉动效,得控制起始点。
关键做法是把下拉容器设为 position: absolute,并用 top: 100% 紧贴父项底部,再配合 transform: scaleY(0) + transform-origin: top 实现纯向下展开:
立即学习“前端免费学习笔记(深入)”;
- 初始:设置
transform: scaleY(0)、transform-origin: top、opacity: 0、visibility: hidden -
:hover时:改为transform: scaleY(1)、opacity: 1、visibility: visible - 过渡写在
transform和opacity上:transition: transform 0.25s ease-out, opacity 0.2s ease - 注意:
visibility不能加 transition,它只负责开关渲染,避免鼠标移入空白区触发误 hover
移动端点击失效?:hover 在触摸设备上的兼容陷阱
很多安卓/iOS 浏览器对纯 :hover 支持不稳定——首次点击可能只触发 :hover,第二次才真正跳转;或者 hover 状态不自动清除,导致下拉卡住。
这不是 bug,而是规范行为::hover 在触摸设备上本就语义模糊。真实项目里必须补充 JS 控制逻辑:
- 给导航父项加
role="button"和tabindex="0",支持键盘焦点 - 监听
click和keydown(Enter/Space),手动切换aria-expanded和 class - CSS 中同时写
.nav-item:hover .dropdown, .nav-item[aria-expanded="true"] .dropdown,让样式响应两种状态 - 别依赖
@media (hover: hover)做完全隔离——它在部分 iPadOS 版本下返回错误值
为什么子菜单悬停延迟关闭很重要
鼠标从父项移到下拉项途中,如果间隙稍大,:hover 状态会立刻丢失,下拉框闪退。这是最常被忽略的交互断裂点。
修复方法不是加 delay(CSS 不支持 hover delay),而是「补全悬停热区」:
- 给父项和下拉容器之间加一个透明的「连接条」:
margin-bottom: -1px或用::after伪元素向下延伸几像素 - 更稳妥的是用
pointer-events: none配合绝对定位覆盖间隙区域 - 或者直接让下拉容器
top: calc(100% - 2px),和父项重叠 2px,消除物理间隙 - 同时确保下拉容器有足够
padding-top,避免鼠标一进就触发子项 hover,造成抖动
动效本身只是表象,真正的难点永远在边界条件:悬停中断、触控歧义、焦点管理、间隙容错。这些地方没处理好,再顺滑的 transform 也救不回体验。


















