不必须但强烈建议用 包裹侧边栏 ul,以确保语义化、seo 和可访问性;非导航内容应分离,避免冗余 dom; 无需 role="link";小屏收起需用 max-height+aria-expanded;:active 应作用于 而非 。

ul 侧边栏结构必须用 nav 包裹吗?
不是必须,但强烈建议。语义化是关键——<nav></nav> 明确告诉浏览器和辅助设备这是导航区域,对 SEO 和屏幕阅读器友好。如果只是页面内普通跳转链接(比如锚点),<aside></aside> 或纯 <div> 也能用,但会丢失导航意图。<p>常见错误:直接把 <code><ul></ul> 塞进 <header></header> 或 <footer></footer> 里却不加语义包装,导致结构混乱、可访问性下降。
- 优先用
<nav><ul>...</ul></nav> - 若侧边栏含非导航内容(如广告、作者信息),导航部分单独抽离为
<nav></nav> - 避免嵌套多层
<div> 包裹 <code><ul></ul>——增加无意义 DOM 节点li 里的链接要不要加 role="link"?
不需要。原生
<a></a>标签自带role="link",手动加反而可能干扰默认行为,尤其在旧版 Safari 或某些读屏软件中引发重复播报。真正要注意的是 href 值:空字符串
href=""或href="#"会导致页面跳顶、破坏历史记录,且无法被键盘用户正确聚焦。- 内部锚点用
href="#section-1"(确保目标元素有对应id) - 外部链接用完整 URL,如
href="https://example.com/about" - JavaScript 驱动的链接,至少提供
href="javascript:void(0)"并绑定click事件,同时加tabindex="0"支持键盘聚焦
如何让 ul 侧边栏在小屏下收起?
靠 CSS 媒体查询 + 状态切换,别用 JS 操控 display 属性隐藏整个
<ul></ul>—— 这会让屏幕阅读器直接忽略全部链接。正确做法是用
max-height+overflow控制展开/收起,并配合aria-expanded和aria-controls维护可访问性状态。ul.sidebar-menu { max-height: 0; overflow: hidden; transition: max-height 0.3s ease-out; } ul.sidebar-menu[aria-expanded="true"] { max-height: 300px; /* 根据实际行数调整 */ }- 触发按钮需有
aria-expanded属性,值随菜单状态同步更新 - 给
<ul></ul>加id,按钮用aria-controls="sidebar-menu-id"关联 - 避免用
visibility: hidden或opacity: 0隐藏菜单——链接仍可聚焦、仍被读屏器读取
为什么点击 li 后 active 样式不生效?
因为
<li>本身不响应 :active 伪类——只有可交互元素(如<a></a>、<button></button>)才支持。很多人写li:active { color: red; },结果完全没反应。正确方案是把 :active、:hover、.active 类都作用在
<a></a>上,并通过 JS 或服务端逻辑控制 class 的增删。- 样式写成
a:active, a.active { color: #007bff; } - JS 切换时操作
event.target.closest('a').classList.add('active') - 若用路由库(如 React Router),优先用其内置的
NavLink或useMatch获取激活状态
容易忽略的一点:移动端 touch 设备上 :active 只在手指按下瞬间触发,持续时间极短,所以视觉反馈必须足够明显(比如背景色+文字色双变),否则用户感知不到已点中。
- 内部锚点用











