details + summary 可原生实现语义化多层选项卡,无需 JS 即支持展开收起、键盘导航与屏幕阅读器,比手写 div 更轻量稳定;需避免嵌套混乱、summary 内嵌 button、display: none 隐藏等常见错误,CSS 可控箭头、缩进与动效,JS 仅用于全区域点击或单开增强,移动端需注意 Safari 兼容性。

用 details + summary 实现语义化多层选项卡
原生 HTML 就能做,不用 JS 也能展开收起,而且天然支持键盘焦点和屏幕阅读器。关键是它比手写 div + click 事件更轻、更稳、更可访问。
常见错误是把多个 details 套在一起却没处理嵌套关闭逻辑——浏览器默认允许子 details 独立开关,但视觉上容易混乱;另一个坑是直接用 summary 里塞 button,会导致双击或焦点行为异常。
-
details默认关闭,加open属性可默认展开 - 每个
summary只能有一个直接子节点(文本或行内元素),否则部分浏览器会忽略后续内容 - 嵌套时,子
details不会影响父级的展开状态,无需额外 JS 干预 - 用 CSS 控制箭头图标:通过
summary::marker或自定义background替换默认三角
CSS 控制层级缩进与箭头样式
纯 CSS 就能做出清晰的树形缩进和统一箭头,避免用空格或 硬调格式。
重点在于区分层级和状态:details[open] summary::marker 改向下箭头,details:not([open]) summary::marker 改向右箭头;缩进靠 padding-left 配合层级 class 或属性选择器实现。
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 给第一层
details加class="level-1",第二层加class="level-2",然后用.level-2 { padding-left: 24px; } - 禁用默认 marker:先写
summary::marker { content: none; },再用background+width/height手动画图标 - hover 和 focus 状态下加背景色,提升可点击感知——尤其对触屏用户很重要
- 别用
display: none隐藏details内容,会导致语义丢失;改用opacity: 0; height: 0; overflow: hidden;配合 transition 做淡出
需要 JS 增强时只补关键行为
只有两个场景真值得加 JS:一是点击任意区域都触发展开(不只是 summary),二是限制单开(同一级只能开一个)。
强行给整个 details 绑 click 会破坏可访问性——屏幕阅读器用户可能误操作;而“单开”逻辑若不加节流或状态清理,容易导致多个同时打开后无法恢复。
- 实现全区域点击:监听
details的click,检查event.target === event.currentTarget,再手动切换open属性 - 单开逻辑只需管同级兄弟节点:
el.parentElement.querySelectorAll('details').forEach(d => d !== el && (d.open = false)) - 避免在
summary上加onclick="..."行内脚本,跟语义化初衷冲突 - 如果菜单项含链接,确保
a标签不在summary内——否则点击链接会先触发展开,再跳转,体验断裂
移动端适配与 Safari 兼容注意点
Safari 对 details 的支持从 iOS 12 / macOS Mojave 开始完整,但老版本仍会降级为静态列表。没有 polyfill 能完美模拟原生行为,所以得接受“不支持就平铺显示”这个事实。
最大实际问题是 iOS 上 details 内部滚动卡顿,以及 Safari 对 summary::marker 的渲染偏移。不是 bug,是渲染管线限制。
- 在 iOS 上避免给
details设固定max-height,改用height: auto配合overflow-y: auto于内部容器 - Safari 中
summary::marker垂直居中异常?加line-height: 1;和vertical-align: middle;试试 - 不要依赖
transition动画控制details显隐——Safari 不触发重排,动画无效;改用@keyframes+transform模拟 - 如果项目必须兼容 iOS 11 及以下,老老实实用
div+aria-expanded+ JS,别硬套details
多层选项卡真正的难点不在结构,而在状态同步和可访问性边界——比如子菜单展开时,父菜单是否该高亮?键盘 Tab 是否该跳过已关闭的子项?这些细节没人提,但用户每天都在遭遇。


















