纯HTML+CSS可实现Mega Menu但不健壮,关键在hover与click状态协同:需用visibility: hidden+opacity: 0替代display: none隐藏菜单,配合JS管理.closed状态、aria属性及键盘/移动端交互支持。

纯 HTML + CSS 能做出可用的 mega menu,但“可用”不等于“健壮”——关键在 hover 与 click 的状态协同,否则移动端失效、键盘用户卡死、关闭后无法再展开。
为什么 :hover 在 mega menu 里经常失灵
很多人写完 .nav-item:hover .mega-menu { display: block; },发现点关闭按钮后菜单再也出不来。根本原因是:display: none 会让元素彻底退出渲染树,:hover 失效,且无法响应后续悬停事件。
- 错误做法:点击关闭直接加
class="hide"并设display: none - 正确思路:用
visibility: hidden+opacity: 0隐藏,保留元素在文档流中、能接收鼠标事件 - 必须配合 JS 清除关闭状态:当用户再次
mouseenter导航栏或 mega menu 自身时,移除.closed类
classList.add('closed') 和 display: none 别混用
使用 .closed 类只是标记“当前被用户主动关闭”,不是物理移除。CSS 中要避免 .closed { display: none; } 这种写法。
- 推荐 CSS 写法:
.mega-menu.closed { visibility: hidden; opacity: 0; } - 悬停生效规则必须带
:not(.closed),例如:.nav-menu:hover + .mega-menu:not(.closed) - 如果用了
display: none,哪怕 JS 后续删掉.closed,也要等一次重绘+重排才可能恢复 hover,体验断裂
移动端和键盘用户的两个硬性补救点
仅靠 :hover 做触发,在手机上完全无效;屏幕阅读器也无法识别“悬停即展开”。必须补上可访问性支持。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
立即学习“前端免费学习笔记(深入)”;
- 给触发项(如
<li class="has-mega-menu">)加上aria-haspopup="true"和aria-expanded="false" - 用
click事件替代mouseenter绑定在移动端(可通过matchMedia检测(hover: hover)区分) - 键盘用户需要
Enter或Space触发展开,同时支持Escape关闭,这些无法靠纯 CSS 完成
别跳过 :focus-within 和 :has() 的渐进增强
CSS 新特性能让逻辑更干净,但得注意兼容性底线。Chrome 105+、Firefox 103+ 支持 :has(),Safari 15.4+ 开始支持,IE 全挂。
- 用
.nav-menu:focus-within .mega-menu可覆盖键盘聚焦场景,比监听每个子项更简洁 -
:has(> .has-mega-menu:focus)能精准匹配焦点落在触发项内的情况,避免误触 - 若需兼容旧浏览器,仍得回退到 JS 控制
aria-expanded和类名切换,不能只依赖 CSS
真正难的不是写出第一版 mega menu,而是让「关闭后再悬停还能出来」「手机点开后能点空白收起」「盲人用户能用键盘完整操作」这三件事同时成立——状态管理漏一环,整个交互链就断了。


















