是当前最轻量、可访问性最强的 faq 组织方式,无需 js 即支持键盘操作、屏幕阅读器识别和 seo 友好结构,因其原生支持 open 属性、空格/回车响应及 role="button" 语义。

用 <details></details> + <summary></summary> 是当前最轻量、可访问性最强的 FAQ 组织方式,不需要 JS 就能支持键盘操作、屏幕阅读器识别和 SEO 友好结构。
为什么不用 <dl></dl> 而选 <details></details>
<dl></dl> 语义正确,但原生不支持折叠/展开交互;用户必须滚动查看全部答案,对长 FAQ 页面体验差。而 <details></details> 天然带 open 属性、响应空格/回车、自动获得 role="button",屏幕阅读器会读作“可展开的问题”,比 <dl></dl> 更主动传达交互意图。
常见错误是把 <summary></summary> 包在 <p></p> 或 <div> 里——这会让折叠逻辑失效,因为 <code><summary></summary> 必须是 <details></details> 的**首个子元素**。
- 正确:
<details><summary>问题</summary><p>答案</p></details> - 错误:
<details><p><summary>问题</summary></p> <p>答案</p></details>
如何让每个 FAQ 支持 URL 锚点跳转并自动展开
浏览器不会自动展开带 hash 的 <details></details>,必须加少量脚本监听 hashchange 并设 open = true。ID 命名要规范:不能含空格或中文标点,推荐小写连字符(如 id="how-to-reset-password")。
关键点:
- 每个
<details></details>必须有唯一id - 脚本需在 DOM 加载后执行(如放在
DOMContentLoaded里) - 展开后调用
scrollIntoView()前,先设open = true,否则可能滚不到隐藏内容 - 加
scroll-margin-top: 80px防止被固定导航栏遮挡标题
怎么写结构化数据(Schema)让 Google 识别为 FAQ 富文本
Google 不看 HTML 标签,只认 JSON-LD 中的 FAQPage Schema,且必须嵌套在 WebPage 类型下。常见失败原因是把 FAQPage 当顶层类型,或把带 HTML 标签的答案塞进 text 字段。
必须满足:
- 外层
@type是"WebPage",不是"FAQPage" -
mainEntity是数组,每个元素是Question类型 -
Question.name和acceptedAnswer.text必须是纯文本(无<p></p>、<strong></strong>) - 从页面提取答案时,用
textContent而非innerHTML,再用JSON.stringify()序列化
容易被忽略的可访问性细节
视觉上做对了不代表可访问。比如自定义图标替换 <summary></summary> 默认箭头时,很多人只处理 Webkit 内核,漏掉 Firefox/Safari 的 ::marker 或 ::before 兼容;又比如给 <summary></summary> 加 tabindex="-1" 会导致键盘无法聚焦——它本来就是可聚焦的,加了反而破坏原生行为。
还有两个硬伤常被忽视:
- 没给
<details></details>加aria-expanded同步状态(虽然原生已隐含,但部分旧版辅助工具仍依赖该属性) - 多个 FAQ 区块共存时,只给第一个区块写了 Schema,第二个靠 JS 动态加载的就没补全
mainEntity











