最轻量横排标签页应使用+配合display: flex容器、white-space: nowrap及flex-shrink: 0实现;需手动处理手风琴互斥、动态max-height缓存、移动端焦点与可访问性同步。

用 <details></details> + <summary></summary> 实现横排标签页折叠最轻量
横排标签页(比如顶部导航栏下的子菜单、工具栏分组)本身不是标准标签页控件,但若想“点击标题展开一列横向内容”,<details></details> 是唯一无需 JS 就能保状态、保语义、保键盘可访问的原生方案。它不强制垂直布局,只要 CSS 把 <summary></summary> 和内部内容设为 display: inline-flex 或 display: flex,就能横排展开。
常见错误是直接套用手风琴结构,把多个 <details></details> 并列写成块级流,结果横向空间被撑开或换行。正确做法是:外层用 display: flex 容器包住所有 <details></details>,每个 <details></details> 设 white-space: nowrap,内部 <summary></summary> 用 flex-shrink: 0 防压缩,展开内容用 position: absolute 或 display: flex 横向铺开。
-
<details></details>必须包含且仅含一个<summary></summary>,且必须是第一个子元素;放<div> 或 <code><span></span>包裹内容没问题,但别在<summary></summary>里塞<div> <li>Safari 对 <code><details></details>的::marker自定义支持弱,横排时三角图标可能错位,建议用summary::marker { display: none; }+ 自定义 SVG 图标替代 - 默认展开用
open属性即可,但无法用 CSS 动态控制 open 状态——那是 JS 才能做的事 - 展开前先设
max-height: 0,再强制重排(offsetHeight读一下),再设max-height: [缓存值],否则动画不会触发 - 收起时设
max-height: 0后,加transitionend监听,结束后再设display: none,不然会影响下一次展开的scrollHeight计算 - 如果横排内容里有图片,得等
img.onload或用loading="lazy"+decode()确保尺寸稳定后再缓存高度 - 监听事件要委托到父容器,避免每个
<details></details>单独绑,尤其横排项多时性能差 - 用
event.target.closest('details')定位触发源,再用parent.querySelectorAll('details')拿全部,过滤掉自己 - 关闭兄弟时,先检查它们是否已
hasAttribute('open'),避免无谓 DOM 写入 - 用
details:not([open]) .submenu这类选择器统一控制隐藏样式,别靠 JS 逐个加 class,维护成本高 - 横排热区(如
<summary></summary>)在移动端必须 ≥ 44×44px,CSS 里用min-width: 44px; min-height: 44px;,别依赖 padding 撑开 - 如果横排项内含搜索框或开关,展开时记得把
aria-hidden="false"和tabindex="0"一起还原,否则键盘用户卡死
横排展开内容高度不确定时,max-height 过渡怎么不截断
横排内容常含动态文字、图标或响应式子项,height: auto 不能参与 CSS 过渡,硬写 max-height: 500px 容易撑高或截断。安全解法是用 JS 动态读取 scrollHeight,但只在首次展开时赋值,避免重复重排。
关键点在于:不要每次 toggle 都重新读 scrollHeight,而是在 toggle 前判断目标元素是否已有 data-max-height 缓存值。没有就取一次 scrollHeight 存上,有就直接用。
多个横排标签页要互斥(手风琴),toggle 事件怎么监听和关闭兄弟节点
<details></details> 自带 toggle 事件,但它只告诉你“这个节点状态变了”,不负责关别人。实现横排手风琴,必须手动遍历同级兄弟 <details></details> 并调用 removeAttribute('open')。
注意:别用 element.open = false,它不触发 toggle 事件,屏幕阅读器也感知不到状态变化;必须操作 DOM 属性。
移动端横排标签页折叠后,焦点和可访问性怎么不丢
横排结构在小屏下极易挤压主内容区,用户点开一个标签页,其他横排项可能被挤出视口甚至遮挡。此时单纯 display: none 不够——键盘 Tab 键仍会跳进已隐藏区域,屏幕阅读器也会念出不可见内容。
真正有效的做法是三合一:display: none + tabindex="-1" + aria-hidden="true"。而且这三者必须同步设置,不能只做其一。
横排折叠最难的不是展开动作本身,而是内容高度动态、兄弟互斥逻辑、以及移动端焦点链断裂这三件事同时发生时,如何让状态、样式、可访问性始终对齐。多数翻车都发生在只改了视觉没同步 aria 属性,或者缓存了错误的 scrollHeight 导致后续展开永远截断。











