details 标签可零JS实现菜单交互,但仅是视觉复用而非语义替代;需重置样式、添加tabindex、自定义箭头并注意键盘支持与焦点管理。

details 标签本身就能做菜单,但得理解它的默认行为
details 是原生 HTML 交互元素,点击 summary 就会切换 open 状态,不需要 JS。但它不是“菜单”语义——它表示“可选的额外信息”,浏览器默认渲染为带小三角的折叠块。用它做菜单,本质是视觉复用,不是语义替代。
- 浏览器对
details的样式控制有限,比如无法直接改小三角图标(需用::marker或覆盖伪元素) -
summary默认是块级、带 margin,容易撑开布局,需重置 - 不支持键盘展开(Enter/Space 触发)的旧版 Safari(<16.4)要留意,但现代主流已支持
如何让 details 看起来像一级菜单项
目标是:点击文字就展开,不依赖 JS,且保持可访问性。
- 给
summary加tabindex="0",确保键盘可聚焦(部分老浏览器需要) - 用
display: block和margin: 0清掉默认外边距 - 隐藏原生 marker,用背景图或伪元素自定义箭头(例如:
summary::marker { content: "" }) - 展开时给
details[open] summary加下划线或背景色,提供视觉反馈
<details>
<summary tabindex="0">产品列表</summary>
<ul>
<li><a href="/prod/a">A 型号</a></li>
<li><a href="/prod/b">B 型号</a></li>
</ul>
</details>嵌套多级菜单?details 套 details 可以,但有坑
可以写 details 里再包一个 details,实现二级折叠。但注意:
- 每层
summary都要设tabindex="0",否则键盘用户进不去子级 - CSS 层叠容易失控,比如
details[open] ul和details details[open] ul要分开写 - 移动端点击区域小,建议给
summary加padding(至少 1rem),避免误触 - 不要指望它自动处理“单开多关”逻辑——原生
details各自独立,多个同时展开完全正常
为什么不用 JS 更干净,但也要接受它的边界
零 JS 的好处是加载快、无依赖、天然支持屏幕阅读器(open 属性会被朗读)。但它不提供:
立即学习“前端免费学习笔记(深入)”;
- 动画过渡(CSS
max-height+overflow模拟很脆弱) - 点击非
summary区域收起(比如点空白处关闭) - URL 锚点联动(如
#section2自动展开对应details)
这些地方一旦真有需求,就得加 JS,而不是硬用 CSS 折腾。别为了“零 JS”牺牲可用性。
细节上最容易被忽略的是焦点管理——当用键盘打开一个 details,焦点不会自动跳进里面的内容区;如果子菜单项很多,用户还得手动 Tab 多次。这个体验断点,光靠 HTML 搞不定。



















