原生 details+summary 可实现语义化垂直折叠菜单,无需 js 或 css 框架,天然支持可访问性与键盘操作;需严格遵循 dom 嵌套规则、合理用 css 微调样式,并通过 @supports 降级兼容 ie。

用 details 和 summary 实现语义化垂直折叠菜单
原生 HTML 就能做,不需要 JS 或 CSS 框架。浏览器兼容性足够(Chrome 12+、Firefox 49+、Safari 12.1+、Edge 79+),details 默认折叠,点击 summary 展开/收起,天然支持键盘操作和屏幕阅读器。
常见错误是手动写 div + JS 控制显隐,既增加代码量又破坏可访问性。真正该做的,是让 details 套嵌多层,或配合少量 CSS 微调样式:
-
summary内可放任意内容(图标、文字、小箭头),但不要加onclick或event.preventDefault(),会干扰默认行为 - 若需默认展开,加
open属性:<details open></details> - 多个
details并列就是垂直风琴效果;想实现“单开一栏”,得用 JS 监听toggle事件并手动关闭其他项
用 CSS 控制折叠箭头和间距,避免重写结构
默认 summary 左侧有个小三角,但位置固定、不可控。想统一右对齐、换图标、加过渡动画,只需覆盖 summary::marker 或用伪元素:
details summary {
list-style: none;
padding: 8px 12px;
cursor: pointer;
}
details summary::after {
content: "▼";
float: right;
transition: transform 0.2s;
}
details[open] summary::after {
transform: rotate(180deg);
}
details summary:focus {
outline: 2px solid #007bff;
}
注意:别用 display: flex 直接包裹 summary 子元素,会破坏 summary 的交互区域;如需布局,用 grid 或 inline-flex 更稳妥。
嵌套子菜单时,details 必须直接包住 summary,不能隔层
以下写法无效(div 隔开了):
<details><div><summary>一级</summary></div> <div>内容</div> </details>
正确嵌套方式(子 details 放在父 details 的内容区,且紧贴 summary 后):
<details><summary>前端</summary><p>基础技术</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5806" title="html-deploy"><img src="https://img.php.cn/upload/skill/000/000/081/179066538882434.jpg" alt="html-deploy" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill5806" title="html-deploy" class="overflowclass">html-deploy</a> <p class="overflowclass">使用 htmlcode.fun 将 HTML 内容或文件部署到网页,适用于用户要求“部署到网页”“托管此 HTML”“生成此前端...的实时链接”等场景。</p> </div> <a rel="nofollow" href="/xiazai/skill5806" title="html-deploy" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> <details><summary>CSS</summary><p>布局与动画</p> </details><details><summary>JS</summary><p>DOM 操作</p> </details></details>
否则子项无法触发,或者展开后空白——这是最常被忽略的 DOM 结构约束。
IE 不支持 details?用 @supports 安全降级
IE 完全不识别 details,会把整个标签当普通容器渲染(内容始终可见)。别用 UA 判断,改用特性检测:
@supports not (display: details) {
details {
display: block;
}
details > *:not(summary) {
display: none;
}
details[open] > *:not(summary) {
display: block;
}
}
这样既保持现代浏览器原生行为,又让 IE 显示为静态列表(虽无交互,但内容不丢失)。如果必须支持 IE 的折叠功能,才引入轻量 JS 库(如 details-polyfill),而非重写整套逻辑。
真正麻烦的不是写代码,而是忘记 details 的 DOM 层级限制和可访问性设计意图——它不是装饰性组件,而是语义容器。动它之前,先确认是否真需要 JS 干预。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










