问答列表应使用而非,因原生支持“问题-答案”键值对语义,可为设id实现锚点跳转,天然缩进且便于JS/CSS控制显隐,屏幕阅读器能准确播报“术语:问题?定义:答案”,而错误传达线性顺序,导致语义断裂、交互僵硬、样式失控。

ol 不适合直接做问答列表——它表达的是不可交换的线性顺序,而问答本质是“问题→回答”的成对映射,不是“第1问、第2问、第3问”这种执行序列。
为什么用 ol 做问答会出问题
常见错误是把每个问答对塞进一个 li,比如:
<ol> <li><strong>Q:怎么重置密码?</strong><br>A:点击登录页右下角「忘记密码」…</li> <li><strong>Q:能换绑手机号吗?</strong><br>A:进入「账号设置」→「安全中心」…</li> </ol>
这看似能编号,但实际埋了三个坑:
- 语义断裂:
ol告诉浏览器“这些项有严格先后依赖”,但问答之间通常无执行先后关系;屏幕阅读器会读作“第一项,第二项”,无法识别“这是个问题,下面是它的答案” - 结构僵硬:没法单独折叠/展开某个回答,也没法给问题加
id锚点跳转(li不是语义化标题容器) - 样式失控:用
type或start控制编号毫无意义,用户根本不在意“这是第几个问题”,而在意“能不能快速定位到我要的答案”
真正该用的标签组合是 dl + dt + dd
dl(definition list)是 HTML 原生为术语-定义、问题-回答这类键值对设计的语义容器,比硬套 ol 更轻、更准、更可访问。
立即学习“前端免费学习笔记(深入)”;
正确写法示例:
<dl> <dt id="reset-pw">怎么重置密码?</dt> <dd>点击登录页右下角「忘记密码」,按邮件提示操作即可。</dd> <dt id="change-phone">能换绑手机号吗?</dt> <dd>进入「账号设置」→「安全中心」→「更换手机号」,需短信验证。</dd> </dl>
优势很实在:
-
dt天然支持id,用户可直接链接到特定问题(如#reset-pw) -
dd默认缩进+语义明确,JS 控制显隐、CSS 加箭头或边框都干净利落 - 屏幕阅读器会读作“术语:怎么重置密码?定义:点击登录页……”,逻辑清晰
- 无需任何 CSS 就能通过
dl dt::before注入问号图标,不破坏语义
如果非要编号显示,别动 ol,用 CSS counter 给 dt 加序号
想保留“Q1、Q2”视觉效果,又不想牺牲语义?直接在 dt 上用 CSS 计数器:
<style>
dl { counter-reset: qno; }
dt { counter-increment: qno; }
dt::before { content: "Q" counter(qno) ": "; font-weight: bold; }
</style>
这样既保持 dl 的语义完整性,又获得可控编号,且支持倒序、跳号、前缀等所有 counter 能力。比在 ol 里塞问答再 hack 样式靠谱得多。
最常被忽略的一点:问答列表的“可访问性优先级”远高于“编号是否从1开始”。用错标签,后期加 ARIA 属性补救的成本,远高于一开始就选对 dl。



















