默认不支持多级嵌套与自动互斥展开,需js手动控制open属性实现手风琴效果,并注意样式重置、a11y增强及移动端兼容性。

details 标签默认不支持多级嵌套展开
直接套用 <details></details> 做步骤条时,很多人发现点击某一步骤后,其他已展开的步骤不会自动收起——这不是 bug,而是 <details></details> 的原生行为:每个实例完全独立,无状态联动。如果你需要「手风琴」效果(即一次只展开一项),必须手动控制 open 属性。
常见错误是只写 <details><summary>步骤1</summary>...</details> 然后期待浏览器自动互斥,结果所有步骤都能同时开着,UI 显得松散且信息过载。
- 真正要实现单步展开,得用 JS 监听
summary点击,遍历所有<details></details>元素,对非当前项调用removeAttribute('open') - 注意不要用
toggleAttribute('open', false),它在某些旧版 Safari 中会把open变成字符串"false",导致元素仍被渲染为展开态 - 如果步骤内容含表单或焦点元素,收起前建议先 blur 当前焦点,避免键盘操作异常
summary 里放图标或计数时样式容易错位
<summary></summary> 是可替换元素(replaced element),默认有内建的下拉箭头,且其伪元素 ::marker 在不同浏览器中渲染逻辑不一致。当你在里面加 <span>1.</span> 或 SVG 图标,容易出现文字基线偏移、图标抖动、甚至点击区域变小。
- 最稳妥的做法是重置
summary的默认样式:summary { list-style: none; display: flex; align-items: center; } - 用
::before或<span class="step-num"></span>控制序号,避免和原生箭头争夺空间 - 若需自定义展开/收起图标,别依赖
details[open] summary::after,改用 JS 切换 class,再通过 CSS 控制.is-open .icon::before { content: "▼"; }
无障碍访问(a11y)必须补全 role 和 aria 属性
原生 <details><summary></summary></details> 虽自带基础语义,但作为步骤条使用时,屏幕阅读器无法感知“这是第几步”“共几步”“当前是否完成”。单纯加 aria-label 不够,需组合使用。
- 给每个
<details></details>加role="region"和aria-labelledby指向对应summary的 id - 在
<summary></summary>内用<span aria-hidden="true"></span>包裹装饰性图标,防止冗余朗读 - 若步骤有完成状态(如“已填写”),用
aria-checked="true"或aria-live="polite"动态播报变化
移动端点击区域小导致体验差
很多开发者忽略 <summary></summary> 默认点击热区仅限文字部分,尤其在 iOS 上,手指轻点边缘大概率失效。这不是 CSS padding 能完全解决的问题——因为 <summary></summary> 的点击捕获逻辑在部分 WebView 中有缺陷。
- 给
summary设置min-height: 44px(iOS 推荐最小触控尺寸),并用display: flex+align-items: center垂直居中内容 - 避免在
summary内写长段落或换行,否则line-height会撑高实际可点区域却不响应 - 真机测试时重点看微信内置浏览器和 Chrome for Android,它们对
<summary></summary>的事件委托处理最不稳定
details 在 Safari 15.4 之前不支持 toggleEvent,你得监听 click 并手动判断 open 状态;又比如服务端渲染时若初始设了 open, hydration 后 React/Vue 可能因状态不一致导致闪动。这些都不是文档里显眼写的,但上线后立刻暴露。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











