原生 details 标签不支持手风琴效果,必须用 JavaScript 控制:监听 summary 点击事件,遍历同组 details 元素,仅保留当前项 open=true,其余设为 false;CSS 无法真正修改 open 属性,:has() 仅能视觉压制且兼容性差。

details 标签本身不支持多开,得靠 CSS 控制展开逻辑
原生 <details> 默认是「单开」行为:点一个 <summary>,其他已展开的不会自动收起。想实现手风琴(Accordion)效果——即同一时间只允许一个面板展开——不能只靠 HTML,必须用 CSS 或 JS 干预。
纯 CSS 方案最轻量,核心思路是:利用 <details> 的 open 属性 + 同级相邻选择器 ~,在某个 <details> 被点开时,把后面所有兄弟 <details> 的 open 状态重置为 false。但注意:CSS 无法真正“修改属性值”,所以这个思路行不通。实际可行的是用 JavaScript 监听点击,手动控制。
- 别指望只写 HTML 就能手风琴——
<details>没内置手风琴逻辑 - 用 CSS
:has()可以做视觉压制(比如隐藏其他展开项),但不改变 DOM 状态,且:has()在旧版 Safari 不稳定 - 真实项目中推荐 JS 控制,兼容性好、行为确定
用 JavaScript 绑定 click 事件实现真手风琴
给每个 <details> 的 <summary> 绑 click,触发时遍历所有同组 <details>,只保留当前项的 open 属性,其余设为 false。
const accordions = document.querySelectorAll('.accordion > details');
accordions.forEach(details => {
details.querySelector('summary').addEventListener('click', () => {
accordions.forEach(other => {
if (other !== details) other.open = false;
});
});
});
- 必须用
details.open = false(赋值),不是details.removeAttribute('open'),后者在部分浏览器里不触发重绘 - 建议给手风琴容器加个 class(如
.accordion),避免误操作页面其他<details> - 如果页面有服务端渲染或动态插入内容,记得对新节点也执行绑定
summary 里的箭头图标要随 open 状态翻转
用 CSS 的 details[open] summary::after 可以控制箭头方向,但要注意默认 <summary> 是可聚焦元素,键盘用户按空格/回车也会触发展开,图标状态必须同步。
立即学习“前端免费学习笔记(深入)”;
summary::after {
content: "▶";
margin-left: 8px;
transition: transform 0.2s;
}
details[open] summary::after {
content: "▼";
transform: rotate(90deg);
}
- 别用
transform: rotate(0deg)和rotate(90deg)做开关——因为初始状态没open属性,details[open]才生效,所以默认箭头必须用content定义 - 如果用了 SVG 或字体图标(如 Font Awesome),改
transform更稳妥;用 Unicode 箭头则直接换content更简单 - 别忘了加
transition,否则翻转会突兀
移动端点击穿透和 focus 样式容易出问题
iOS Safari 对 <summary> 的 focus 处理比较特殊:点击后可能不触发 :focus,或者焦点残留导致下一次点击失效。同时,某些安卓 WebView 里,快速连点会导致 open 状态错乱。
- 给
summary加touch-action: manipulation减少延迟 - 移除默认 outline:用
summary:focus { outline: none; },但务必提供替代视觉反馈(比如背景色变化) - 防连点:在 JS click 处理器里加
if (details.open) return,避免重复 toggle - 不要用
pointer-events: none去“优化”点击区域——这会让键盘导航完全失效
open 属性和语义化结构来保障,不是加个 JS 就完事。



















