用<details>+<summary>可实现无需JavaScript的语义化下拉菜单,它原生支持键盘操作、屏幕阅读器及aria-expanded,默认收起,加open属性可默认展开,但IE不支持,且无法自动互斥或点击外部收起。

如何用原生 HTML + CSS 实现点击展开的下拉按钮
不需要 JavaScript 就能做出基础版下拉菜单,但必须用 <details> + <summary> 组合。这是唯一被浏览器原生支持、语义正确、且自带 ARIA 属性的方案。
常见错误是硬套 <div> + onclick 模拟,结果键盘无法聚焦、屏幕阅读器不识别、移动端点透或失焦关闭异常。
-
<details>默认收起,open属性控制初始状态(如<details open>) -
<summary>内容自动获得role="button"和aria-expanded,无需手动补 - 样式可覆盖默认箭头:用
summary::marker或summary::-webkit-details-marker - 不支持 IE,Edge 79+、Chrome 12+、Firefox 49+ 可用;Safari 12.1+ 支持完整语义
用 JavaScript 补足 <details> 缺失的能力
原生 <details> 无法监听“展开完成”时机、不能动态插入菜单项、也不支持点击区域外自动收起——这些得靠 JS 补。
关键不是重写整个下拉逻辑,而是最小干预:只监听 toggle 事件,再按需操作 DOM。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 监听
details.addEventListener('toggle', handler),比监听click更准确(避免重复触发) - 收起时清空动态生成的子菜单项,否则下次展开可能残留旧内容
- 点击外部关闭:用
document.addEventListener('click', ...),但要排除details及其子元素(检查e.target.closest('details')) - 不要用
setTimeout延迟收起——会导致点击菜单项时菜单闪退;改用focusout或blur配合防抖
下拉菜单项里放表单控件(如 <input>、<select>)的坑
把输入框塞进 <details> 里,最常遇到两个问题:焦点丢失、滚动错位。
根本原因是 <details> 的展开动画由浏览器控制,而 input 聚焦会强制滚动到可视区,两者冲突。
- 禁用原生展开动画:加 CSS
details[open] { animation: none; },再用max-height+transition手动控制(更可控) -
<input>聚焦后,若菜单高度变化导致滚动,手动调用input.scrollIntoView({ block: 'nearest' }) - 避免在
<summary>里放<input>—— 会破坏按钮语义,且 Safari 下点击输入框不触发toggle - 如果必须嵌套表单,把
<form>提到<details>外层,用form.target或事件委托处理提交
移动端适配:触摸、滚动与键盘焦点的协同
在 iOS Safari 和 Android Chrome 上,<details> 的 touchstart 和 focus 顺序混乱,容易导致点一下没反应、点两下才展开。
这不是 bug,是浏览器为兼容老页面做的妥协:触摸事件默认不触发 focus,而 <summary> 又依赖 focus 状态来激活。
- 给
<summary>加tabindex="0"强制可聚焦(原生已支持,但某些安卓 WebView 需显式声明) - 避免同时监听
touchstart和click—— 移动端会触发两次,用if ('ontouchstart' in window) { ... } else { ... }分流 - 菜单展开后,禁止背景滚动:给
body加overflow: hidden,但记得收起时恢复(别用!important,用 class 切换) - 返回键收起菜单:监听
window.onpopstate不够可靠,优先用details.addEventListener('toggle', ...)+history.pushState()手动管理状态
真正麻烦的不是实现,而是不同浏览器对 details 的 focus、animation、touch 响应节奏不一致。测试至少要覆盖 iOS 16+ Safari、Android 12+ Chrome、Windows Edge 最新版。


















