details标签不适合做侧边栏菜单,因其仅支持summary点击展开、缺乏遮罩关闭/动画/键盘导航/无障碍语义;推荐用checkbox+label+css实现纯css开关式侧边栏,details仅宜作为侧边栏内折叠区块。

details 标签本身不支持嵌套导航菜单结构
直接用 <details></details> 做侧边栏导航菜单,会遇到两个硬伤:一是它默认只响应点击,无法通过键盘(如 Tab + Enter)触发,不符合可访问性要求;二是内部的 <summary></summary> 无法被屏幕阅读器识别为可交互菜单项,且浏览器不会将其纳入焦点流。更关键的是,<details></details> 的语义是「可展开的额外信息」,不是「导航容器」——用它替代 <nav></nav> 或带角色的列表,会让辅助技术误读整个导航逻辑。
如果你只是想快速实现视觉上的折叠/展开效果,又不想引入 JS 框架,可行路径是:用语义正确的 HTML 结构(<nav></nav> + <ul></ul>),再用 CSS 模拟 <details></details> 的行为,同时保留焦点和键盘支持。
用 CSS 实现类 details 折叠效果(无 JS)
核心思路是利用 <input type="checkbox"> 的状态切换 + :checked 伪类控制显示,配合 ~ 或 + 选择器影响后续兄弟元素。这样既保持语义清晰,又能免 JS 实现收展。
- 把每个导航分组包装成一个
<li class="nav-group">,内部含<input id="group1">、<label for="group1"></label>和<ul class="submenu"></ul> -
<label></label>替代<summary></summary>,它天然可聚焦、可键盘操作、语义明确 - 初始隐藏子菜单:
.submenu { display: none; };激活时显示:input:checked ~ .submenu { display: block; } - 添加
aria-expanded属性并用 JS 同步更新(非必须但推荐),否则纯 CSS 方案无法自动通知屏幕阅读器状态变化
示例片段:
<nav aria-label="侧边栏导航"><ul>
<li class="nav-group">
<input type="checkbox" id="menu-docs"><label for="menu-docs" aria-expanded="false">文档</label>
<ul class="submenu">
<li><a href="/guide">入门指南</a></li>
<li><a href="/api">API 参考</a></li>
</ul>
</li>
</ul></nav>
为什么不能直接用 details + summary 做菜单项
常见错误是这样写:
<details><summary>文档</summary><a href="/guide">入门指南</a> <a href="/api">API 参考</a> </details>
问题很具体:
-
<summary></summary>默认是display: list-item,且不可设tabindex,导致键盘用户无法用 Tab 进入、Enter 展开 - 子链接在 DOM 中是
<details></details>的后代,但语义上不属于同一导航层级,屏幕阅读器可能跳过或误读为「文档详情」而非「文档类目下的链接」 - Chrome/Firefox 对
<details></details>内部交互元素的焦点管理不一致,某些版本下展开后焦点不会自动落到第一个子链接上 - 无法用 CSS 精确控制子项的过渡动画(
height: auto不支持 transition),只能靠max-height拼凑,易出高度错位
真正需要 JS 的地方只有两个
如果项目已有 JS 环境,建议只在以下两点增强,其余保持纯 HTML/CSS:
- 监听
change事件同步更新aria-expanded属性值(input:checked ? 'true' : 'false') - 展开后自动将焦点移到第一个子链接(
submenu.querySelector('a').focus()),这对键盘用户至关重要
不要用 JS 控制显隐本身——CSS 已足够稳定;也不要重写整个菜单逻辑为 React/Vue 组件,除非你已在用对应框架。原生方案里,DOM 结构清晰、样式可控、无障碍基础扎实,才是长期可维护的关键。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











