原生 details 不支持嵌套,因 HTML5 规范未定义该行为;外层折叠逻辑中断、open 状态失效、屏幕阅读器无法识别,需改用 div + max-height + JS 方案并手动实现 ARIA 语义与键盘支持。

原生 details 不支持嵌套,强行写会失效
浏览器对嵌套 details 的支持极差:Chrome 和 Firefox 会忽略内层的 open 状态,Safari 直接不响应点击;更关键的是,summary 必须是 details 的**首个子元素**,一旦中间插入另一个 details,外层折叠逻辑就中断。
这不是样式问题,而是 HTML5 规范未定义嵌套行为 —— 所以不是“还没实现”,而是“明确不支持”。常见错误包括:
-
<details><summary>一级</summary><details><summary>二级</summary><p>内容</p></details></details>:外层点不动、二级图标不转、Tab 键跳过二级 - 在
summary外加<div>或注释/空格:Safari 下整个面板失活 - 用
display: none/block控制子级显隐:破坏aria-expanded同步,屏幕阅读器无法识别状态
用 toggle 事件 + data-group 模拟父子联动
若必须保留语义又需要层级联动(比如 FAQ 分类下展开子问题),可监听 toggle 事件手动同步子级状态,但仅限“单向联动”(父开则子开,父关则子关):
- 给每组父子面板加统一
data-group属性,如data-group="faq-1" - 父
details触发toggle时,用querySelectorAll找同组子级,再赋值child.open = panel.open - 避免操作
style.display或hidden,否则toggle事件不触发、键盘不可访问
document.querySelectorAll('details[data-group]').forEach(panel => {
panel.addEventListener('toggle', () => {
const group = panel.dataset.group;
document.querySelectorAll(`details[data-group="${group}"]`).forEach(child => {
if (child !== panel) child.open = panel.open;
});
});
});
真嵌套需求应改用 div + max-height + JS 方案
当子面板需独立开关、动画不同步、或含 <video>/<iframe> 等需生命周期管理时,原生 details 已无优势。此时推荐手写结构:
立即学习“前端免费学习笔记(深入)”;
- 用
<div class="accordion-item">包裹标题与内容,避免语义污染 - CSS 控制
max-height过渡:设足够大值(如500px),而非auto - JS 中用
scrollHeight动态读取内容高度,再赋给style.maxHeight实现精准动画 - 为键盘支持,给标题加
tabindex="0",监听Enter/Space键触发切换 - 多个面板同时展开时,记得加互斥逻辑:
querySelectorAll('.is-open').forEach(el => el.classList.remove('is-open'))
图标旋转和焦点状态容易被忽略
自定义箭头用 ::before 或 ::after 时,details[open] summary::after 只能旋转外层图标;子面板的图标状态不会联动 —— 必须靠 JS 切换类名驱动。
更隐蔽的问题是焦点:summary 自带 role="button" 和键盘支持,但 JS 方案里若用 div 当触发器,必须手动加:
role="button"-
aria-expanded="false"(初始)并随状态更新 -
aria-controls="target-id"关联内容区域
否则视障用户无法感知当前是否展开,也无法用键盘操作。



















