<details> 和 <summary> 可原生实现无障碍、SEO 友好的可折叠 FAQ,无需 JS;需避免自闭合写法、正确使用 open 属性,遵循语义结构与 CSS 微调规范,并为 IE 提供轻量 polyfill 降级。

用 <details> 和 <summary> 实现可折叠 FAQ 最省事
现代浏览器原生支持,不用 JS 就能展开收起,语义正确、无障碍友好、SEO 友好。IE 不支持,但 Chrome/Firefox/Safari/Edge(16+)都行。
常见错误是把 <summary> 写成自闭合标签(<summary />),它必须有结束标签;另外 <details> 默认展开需加 open 属性,不加就是默认收起。
-
<details>包裹整个问答项,每个<details>是独立的,互不影响 -
<summary>只能是<details>的第一个子元素,且只能有一个 - 内容正文直接跟在
<summary>后面,无需额外容器(如<div>),避免嵌套过深影响可访问性
<details> <summary>网页加载慢怎么办?</summary> 可检查网络请求、压缩图片、启用 Gzip,或使用 <code><link rel="preload"></code> 提前加载关键资源。 </details> <details open> <summary>如何让文字居中?</summary> 块级元素用 <code>text-align: center</code>(文本)或 <code>margin: 0 auto</code>(块本身),注意 <code>display</code> 类型影响。 </details>
手动控制展开状态时别直接操作 open 属性
虽然 element.open = true 看似可行,但会绕过浏览器内置的过渡和焦点管理,导致键盘用户按 Enter 无法触发、屏幕阅读器播报异常、动画卡顿。
正确做法是监听 toggle 事件,用 element.hasAttribute('open') 判断当前状态,需要干预时调用 element.setAttribute('open', '') 或 element.removeAttribute('open') —— 这样才能触发浏览器原生行为。
立即学习“前端免费学习笔记(深入)”;
- 不要用
element.style.display = 'block'模拟展开,破坏语义和可访问性 - 避免在
click事件里反复toggleAttribute('open'),可能和原生<summary>点击冲突 - 若需统一收起其他项(单选式 FAQ),应在
toggle事件中遍历兄弟<details>并移除它们的open属性
CSS 排版微调:去掉默认箭头和控制间距
Chrome 和 Safari 默认在 <summary> 左侧加小三角,Firefox 不加。想统一或隐藏,得用 ::marker 或重置 list-style。
常见误区是只写 summary { list-style: none },但不够——某些浏览器仍显示箭头,必须加上 summary::marker { content: "" } 才彻底清除。
- 用
summary { padding-left: 1em }替代默认缩进,避免箭头消失后文字贴边 -
details[open] > summary可单独设置展开时的样式(比如加下划线或变色) - 正文内容默认有上下 margin,若需紧凑排版,建议对
details > *:not(summary)设置margin-top: 0.5em而非全局重置
兼容 IE 或老版本 Edge 时的降级方案
IE 完全不识别 <details>,所有内容默认展开且不可交互。不能靠 CSS 修复,必须用 JS 补充逻辑,但要注意别让现代浏览器重复执行。
最轻量的做法是检测 'open' in document.createElement('details'),为不支持的环境动态插入按钮、绑定 click、切换 aria-expanded 和 hidden 属性 —— 不要替换整个 DOM 结构,保持 HTML 原样可读。
- 降级后务必补全
aria-controls和id关联,否则屏幕阅读器无法理解问答关系 - 避免用
display: none控制显隐,优先用hidden属性,更语义且兼容 JS 失效场景 - 如果项目已用 jQuery,别写
$('details').detailsPolyfill()这类过时插件,现在有更小更靠谱的details-element-polyfill(仅 2KB)
真正麻烦的不是代码怎么写,而是很多人忘了给 <summary> 加 tabindex="0"(其实不用——它天生可聚焦),或者在 polyfill 里漏掉键盘事件(Space/Enter 触发切换)。



















