最稳妥的多级导航实现是语义化嵌套,子菜单为内嵌,配合:hover显示、position:relative/absolute精确定位,并通过JS支持移动端点击及aria属性保障无障碍访问。

用 <ul></ul> 嵌套实现多级结构,别用 <div> 堆砌
<p>纯 CSS 实现多级导航最稳妥的方式是语义化嵌套:<code><ul></ul> 里放 <li>,子菜单就是某个 <li> 内部再套一个 <ul></ul>。浏览器默认会忽略子 <ul></ul> 的显示,靠 :hover 触发 display: block 即可展开。如果用 <div> 或 <code><span></span> 替代 <ul>/<li>
</ul>,键盘焦点、屏幕阅读器支持和 CSS 选择器都会变麻烦。
常见错误是把子菜单写成同级元素(比如所有 <ul></ul> 并列),导致 CSS 无法精准定位到“当前 <li> 下的子 <ul></ul>”。正确结构示例:
<nav>
<ul>
<li><a href="#">首页</a></li>
<li>
<a href="#">产品</a>
<ul>
<li><a href="#">Web 端</a></li>
<li><a href="#">移动端</a></li>
</ul>
</li>
</ul>
</nav>
:hover 触发显示时,必须给父 <li> 设 position: relative
子菜单 <ul></ul> 通常用 position: absolute 定位,否则会撑开父容器、破坏布局。但 absolute 的定位参考点是最近的 position: relative 祖先——如果没显式设置,就可能相对 偏移,导致菜单飘走。
关键 CSS 规则:
立即学习“前端免费学习笔记(深入)”;
- 父
<li>必须加position: relative - 子
<ul></ul>设position: absolute; top: 100%; left: 0;(top: 100%让它紧贴父项底部) - 默认隐藏子菜单:
ul ul { display: none; },再用li:hover > ul { display: block; }触发
漏掉 position: relative 是最常被忽略的一步,调试时看到菜单位置错乱,第一反应就该查这个。
移动端点击展开需用 JavaScript 切换 class,不能只靠 :hover
:hover 在触摸设备上基本失效(iOS Safari 只在模拟悬停后短暂触发一次)。真要支持手机端,得监听点击事件,动态给父 <li> 添加/移除一个类(比如 is-open),再用 CSS 控制 .is-open > ul { display: block; }。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
简单 JS 示例(不依赖框架):
document.querySelectorAll('nav li').forEach(li => {
const subMenu = li.querySelector('ul');
if (subMenu) {
li.addEventListener('click', e => {
e.stopPropagation();
li.classList.toggle('is-open');
});
}
});
注意点:
- 必须
e.stopPropagation(),否则点击子菜单项会冒泡触发父级click,导致菜单闪退 - PC 端仍保留
:hover样式,手机端靠is-open类接管,两者互不干扰 - 别用
display: none配合 JS 切换——CSS 动画不支持display过渡,想加淡入效果得改用opacity+visibility
无障碍访问不能只靠视觉,要补 aria-expanded 和 aria-haspopup
光有下拉箭头图标和 hover 效果,对屏幕阅读器用户是黑盒。每个带子菜单的 <a></a> 必须加上:
-
aria-haspopup="true":声明该元素有弹出内容 -
aria-expanded="false"(初始状态),JS 切换时同步更新为"true"或"false" - 子菜单
<ul></ul>加role="menu",子项<li>加role="menuitem"(非必需但推荐)
例如:<a href="#" aria-haspopup="true" aria-expanded="false">产品</a>。漏掉这些属性,视障用户根本不知道那里能展开,也无从操作。
复杂点不在结构或样式,而在于 hover / click / 键盘焦点 / 屏幕阅读器四者行为要一致——比如按 Tab 聚焦到“产品”链接后,按 Enter 或 Space 也得能展开菜单,且焦点要合理落入子项中。这需要额外的键盘事件处理,不是加个 aria 就完事的。


















