侧边快捷菜单必须用<nav>而非<aside>,因其本质是导航;内部仅允许链接,禁用按钮/搜索框;多级菜单须嵌套<ul>,隐藏时用aria-hidden+inert而非display:none。

侧边快捷菜单必须用 <nav>,不能用 <aside>
侧边快捷菜单本质是导航行为——用户点击跳转、键盘可聚焦、读屏器需识别为“菜单项”,语义上属于主导航范畴。<aside> 表示附属内容(如推荐文章、广告、作者简介),它不参与导航流,也不该被 Tab 键访问。混用会导致焦点丢失、SEO 权重稀释、VoiceOver 读不出菜单数量。
- 正确写法:
<nav aria-label="快捷操作菜单"><ul><li><a href="/export">导出数据</a></li></ul></nav> - 错误写法:
<aside><div><a href="/export">导出数据</a></div></aside>(无语义、不可聚焦、无列表结构) - 若菜单含图标,用
<svg>内联或伪元素,别用<img>破坏文本可访问性
<nav> 里只能放链接,别塞搜索框或按钮
快捷菜单的职责是跳转,不是交互容器。<nav> 内部插入 <button>、<input> 或非链接式触发器,会破坏语义链:浏览器认为这不是纯导航区,:focus-within 失效,键盘 Tab 顺序可能跳过整个区块,下拉子菜单 hover/focus 逻辑也会异常。
- 搜索功能应独立于
<nav>,放在顶部工具栏或<header>内 - “刷新”“折叠”这类操作按钮,如果只是触发 JS 行为且无跳转目标,应移出
<nav>,改用<div role="toolbar">包裹并加aria-label - 所有
<a>必须有有效href(哪怕只是href="#"+event.preventDefault()),否则会被读屏器忽略
多级快捷菜单必须用嵌套 <ul>,禁用 <div> 包裹
下拉/展开类快捷项(如“设置 → 账户”“导出 → PDF/CSV”)依赖语义化嵌套来维持可访问性层级。浏览器和 NVDA 只通过 <nav><ul><li><ul> 这条路径识别父子关系;中间插 <div class="submenu"> 会切断语义,导致子项无法被键盘访问,aria-expanded 和 aria-controls 失效。
- 正确结构:
<li><a href="#" aria-expanded="false">导出</a><ul class="submenu"><li><a href="/export/pdf">PDF</a></li></ul></li> - 子菜单
<ul>必须直接挂在父<li>下,不能外包<div>或<span> - 用
display: none切换子菜单显隐,别用visibility: hidden或opacity: 0,否则读屏器仍会读出隐藏项
移动端折叠时,<nav> 仍需保持语义完整
响应式侧边快捷菜单常在小屏收起为汉堡按钮,但收起后 <nav> 不能销毁或降级为 <div>。隐藏状态要用 aria-hidden="true" + inert 属性控制可访问性,而非移除 DOM 或改标签名——否则屏幕阅读器在展开前就感知不到该导航区存在。
立即学习“前端免费学习笔记(深入)”;
- 展开按钮需用
<button aria-expanded="false" aria-controls="quick-nav">,并绑定id="quick-nav"到<nav> - JS 控制显示时,同步切换
aria-expanded和inert,例如:nav.inert = !expanded - 避免用
display: none直接隐藏整个<nav>,这会让读屏器彻底忽略它;改用visibility: hidden; position: absolute; clip: rect(0 0 0 0)配合aria-hidden



















