原生 和 标签可实现手风琴效果,无需 JavaScript;需确保 是 的第一个子元素且有结束标签;默认样式可通过 CSS 重置,如清除 ::marker、自定义箭头;多组独立展开,单开单关需 JS 监听 toggle 事件控制;兼容性方面 IE 不支持,Safari 15.4+ 才支持 ::marker。

details + summary 标签本身就能实现手风琴,无需 JavaScript
浏览器原生 <details></details> 和 <summary></summary> 组合已内置展开/折叠逻辑,点击 <summary></summary> 自动切换 <details></details> 的 open 属性。这意味着你不需要监听 click、不需维护 state、也不用写 toggle 函数——只要结构正确,行为就可靠。
常见错误是把 <summary></summary> 写成自闭合标签(如 <summary></summary>),或把它放在 <details></details> 外面。必须保证:
-
<summary></summary>是<details></details>的**第一个子元素** -
<summary></summary>必须有结束标签() - 多个
<details></details>并列时,默认各自独立控制,天然符合“手风琴”中“单个展开”的直觉(但注意:它不是强制互斥,要单开单关需额外控制)
默认样式难看?用 CSS 覆盖 summary 的 ::marker 和 outline
Chrome/Firefox 默认会在 <summary></summary> 前加一个三角形标记(::marker),且聚焦时有难看的蓝色外框(outline)。不重置的话,视觉上很割裂。
关键样式建议:
立即学习“前端免费学习笔记(深入)”;
- 清除原生标记:
summary::marker { content: "" } - 移除焦点环(若设计允许):
summary:focus { outline: none };更推荐用outline-offset或自定义 focus 样式替代全删 - 添加自定义箭头更可控:
summary::after { content: "▶"; margin-left: 8px; transition: transform 0.2s; },再配合details[open] summary::after { transform: rotate(90deg) } - 注意:Safari 对
::marker支持较晚(15.4+),旧版本需用list-style: none+position: relative+ 伪元素模拟
让多个 details 实现“单开单关”手风琴(非默认行为)
原生 <details></details> 是完全独立的,点击一个不会关闭其他。要实现经典手风琴(一次只开一个),必须用 JavaScript 监听 toggle 事件并手动关闭兄弟节点。
实操要点:
- 给所有
<details></details>加相同 class(如js-accordion),方便批量操作 - 监听
toggle事件(注意:该事件在open属性改变后触发,且冒泡) - 只在当前
details[open]为 true 时才执行关闭其他逻辑,避免重复触发问题 - 示例代码片段:
document.querySelectorAll('.js-accordion').forEach(item => {
item.addEventListener('toggle', () => {
if (item.open) {
document.querySelectorAll('.js-accordion').forEach(other => {
if (other !== item) other.open = false;
});
}
});
});
兼容性与渐进增强要注意这些点
IE 完全不支持 <details></details>,Edge 15–18 部分支持但无 toggle 事件。如果你必须支持 IE,就得回退到 JS 实现;否则可安全使用,并用 @supports 做样式分层。
实用策略:
- 基础功能不依赖 CSS:即使样式未加载,
<details></details>在支持浏览器里仍可交互 - 用
@supports (display: contents)或更直接地@supports (display: grid) and (not (-webkit-appearance: none))来包裹高级样式(不够精准但够用) - 不要用
appearance: none强制抹除所有原生样式——某些屏幕阅读器依赖默认summary的语义表现 - 移动端点击区域小?给
summary加padding和min-height,别只靠字体大小撑开
细节决定是否真能用:比如 Safari 在 iOS 上对 details[open] 的 CSS 过渡支持不稳定,动画最好只作用于内部内容,而非 <details></details> 自身高度。


















