语义化标签选错,页面在浏览器里照样能渲染,样式也不会立刻出问题,但换到屏幕阅读器、搜索引擎爬虫或文章摘要工具里,结构就可能变得难以理解。要选对标签,核心不是记住某个对照表,而是先判断内容在页面中承担什么角色,再根据角色反向选择标签。比如同样一个内容区块,独立成篇的内容和只作为页面一部分的补充说明,在HTML里对应完全不同的标签。接下来从判断维度、高频标签边界、典型场景组合和可访问性验证几个方向展开。

一、先判断内容角色,而不是先挑标签
选择语义化标签之前,先回答三个问题:这段内容脱离当前页面后还能不能独立阅读?它有没有明确的标题可以概括?它和页面主体内容是并列关系还是附属关系?这三个问题的答案基本上能锁定大多数结构类标签。
如果一段内容可以单独发布到RSS、公众号或转载页面,不会因为脱离原页面而失去完整性,就优先考虑 <article>。相反,如果内容只是页面里一个需要标题分隔的小节,本身不足以独立发布,应该用 <section>。这里最容易犯的错误是把所有带标题的区块都换成 section,或者把登录框、搜索框这类功能性模块硬塞进 article。功能性模块虽然也占据一块区域,但它不被内容分发系统当作一篇文章或独立条目处理,使用 article 会在可访问性树中制造误导。
以登录表单为例,下面两段代码在视觉上可能完全一样,但语义完全不同:
<!-- 不推荐:登录表单不是独立可分发内容 -->
<article>
<h2>用户登录</h2>
<form action="/login" method="post">
<label>邮箱 <input type="email" name="email"></label>
<button type="submit">登录</button>
</form>
</article>
<!-- 更合理:用 section 并关联标题 -->
<section aria-labelledby="login-title">
<h2 id="login-title">用户登录</h2>
<form action="/login" method="post">
<label>邮箱 <input type="email" name="email"></label>
<button type="submit">登录</button>
</form>
</section>
注意,section 也不是 div 的替代品。只有当区块存在自然标题,并且标题能准确描述这个区块的内容时,才应该使用 section。如果一个 div 只是为了方便写样式或挂载脚本,内部没有可供大纲识别的标题,继续使用 div 反而更合适。
二、高频语义化标签的边界与常见误用
先看 <article> 和 <section> 的嵌套。article 内部可以继续使用 section 拆分章节,section 内部也可以出现 article,但前提是里层内容确实具备独立的完整性。比如一篇文章里包含一个独立的扩展阅读卡片,这个卡片就可以用 article 放在 section 内部。反过来,如果只是文章的两个自然段,随便加上 section 只会让文档大纲变得破碎。
<aside> 经常被理解为侧边栏,但它的准确含义是与周围内容相关但不属于主干的附属信息。页面级侧边栏当然可以用 aside,文章内部的补充说明、术语解释、相关链接也可以用 aside。判断标准是:删除这段内容后,主体信息的完整性不应该受影响。如果把正文核心步骤放进 aside,屏幕阅读器用户可能在 landmark 导航里根本注意不到它。
<nav> 和 <header>、<footer> 同样有使用边界。nav 应该只包主要导航区域,比如顶部导航、面包屑、分页。不要给每个链接组都套 nav。一个页面可以有多个 nav,但建议用 aria-label 区分,比如 <nav aria-label="站内导航"> 和 <nav aria-label="分页导航">。header 和 footer 也不只属于页面。article 或 section 内部同样可以有自己的 header 放置标题和元信息,footer 放置脚注、来源、分享信息。页面级 main 则必须唯一,并且不能嵌套在 article、aside、nav、header、footer 中。
三、典型场景下的标签组合方式
文章列表页是最容易用混的场景。列表外层用 <ul> 是合适的,但每条摘要如果只有标题、时间和摘要,仍应使用 article 包裹,而不是让 li 承担整条内容的全部语义。列表只是表示多个条目的排列关系,article 才表示每个条目是可以独立理解的完整单元。示例如下:
<ul class="post-list">
<li>
<article>
<h2><a href="/post/1">语义化标签选择指南</a></h2>
<p>分类:前端优化</p>
<p>如何判断 article 和 section 的使用边界。</p>
</article>
</li>
<li>
<article>
<h2><a href="/post/2">可访问性树与地标导航</a></h2>
<p>分类:无障碍设计</p>
<p>用辅助技术验证语义结构是否合理。</p>
</article>
</li>
</ul>
评论区也是重灾区。评论区整体可以是一个 section,每条评论用 article,因为单条评论在脱离页面后仍能表达一个完整观点。如果评论下还有回复,可以嵌套 article,但不要用 blockquote 替代 article。blockquote 表示引用内容,不等于可独立理解的评论实体。给评论区加标题可以用 <h2> 或 <h3>,并通过 aria-label 或 aria-labelledby 建立关系。
图片配文场景中,只要图片和说明文字存在绑定关系,就应使用 <figure> 和 <figcaption>。但装饰性图片不需要 figure,因为辅助技术通常会直接忽略装饰图,加上 figure 反而多出一个语义结构。表单分组则更适合 fieldset 和 legend,尤其是多选按钮组、地址分组等,不应为了追求语义化而强行使用 section 或 div。
四、用可访问性树验证选择是否合理
选完标签后,最直接的验证方式不是反复翻规范,而是打开浏览器的开发者工具,查看 Accessibility 面板里的可访问性树。article 会映射为 article 角色,带标题的 section 会映射为 region,nav 映射为 navigation,main 映射为主地标。检查这些角色是否出现在不合理的位置,能快速发现误用。
屏幕阅读器用户依赖地标导航和标题导航在页面中快速跳转。如果你把整页所有链接都放进 nav,地标导航会变得冗长;如果把没有标题的 section 随意使用,标题面板里也不会出现任何可跳转条目。这个视角比单纯看HTML代码更能暴露问题。
语义化标签解决的是结构表达,ARIA 解决的是交互和状态表达。二者不能互相替代。一个没有标题的 section 并不会因为加上 role="region" 就自动变得合理,反而应该先检查是否缺少 h2 或 h3。同样,一个交互组件需要 aria-expanded、aria-controls 等状态时,语义化标签本身不会自动补齐这些可访问性信息。最终的选择原则可以归纳为:先看内容是否能独立,再看是否有自然标题,最后用可访问性树验证角色是否符合预期。