语义化标签的常见说法是”有利于 SEO”。这个说法既没法验证也没法证伪,所以我一直没太当回事,直到认真看了一次无障碍树。
真正被”语义化”影响的,是每个元素在无障碍 API 里暴露的 role。读屏、浏览器扩展、自动化测试工具,读的都是它。
默认 role 对照
按 HTML-AAM(HTML Accessibility API Mappings)的规定,常用标签的默认 role 大致是这样:
| 标签 | 默认 role | 备注 |
|---|---|---|
div / span |
generic | 没有语义 |
section |
generic | 只有在有 accessible name 时才升级成 region |
form |
generic | 同上,有 name 才是 form |
article |
article | 无条件 |
nav |
navigation | 无条件 |
aside |
complementary | 无条件 |
main |
main | 每页只能有一个可见的 |
header |
banner | 仅当作用域是 body;在 article / section 里退化成 generic |
footer |
contentinfo | 同上,作用域受限 |
figure |
figure | 无条件 |
最容易搞错的是前两行。我一直以为 <section> 天生就是”区域”——其实不是。没有 accessible name 的 <section>,role 就是 generic,和 <div> 完全等价。要达到”区域”的效果,得给它一个名字:
<section aria-label="最新文章"> … </section>
<!-- 或者 -->
<section aria-labelledby="sec-latest">
<h2 id="sec-latest">最新文章</h2> …
</section>
header 那一行也值得注意:页头和文章内的”文章头”用的是同一个标签,但 role 不同。写在 <body> 直接子级是 banner,写进 <article> 里就不是了——因为”页面的横幅”和”这篇文章的头部”本来就不是一回事。
怎么看自己页面的 role
这里有个坑:role 在 JavaScript 里拿不到。没有标准的 DOM API 能读到计算后的 role,getComputedAccessibleNode 是个已废弃的试验接口。所以只能靠 DevTools:Elements 面板里选中元素,右边切到 Accessibility 标签,看 Computed Role 和 Computed Name。
顺带一个更实用的入口:Accessibility 面板顶部有个「全页无障碍树」视图,能把整页的 role 层级列出来。看一遍就知道自己的页面在工具眼里长什么样——很多时候跟你想象的不一样。
所以语义化该怎么用
一、别把 div 批量换成 section。 一页十几个没有名字的 <section>,在无障碍树里全是 generic,等于十几个 div,还多了一层”我本来想表达点什么”的假象。要么给名字,要么老实写 div。
二、标题层级比容器标签更重要。 读屏用户最常用的导航方式是按 H 键在标题间跳,不是按 region 跳。<h2> 跳 <h4> 这种断级,比 div/section 的选择影响大得多。
三、最便宜的三个改进。 <nav> 包导航、<main> 包主内容、给 main 加个 id 配一个”跳到主内容”的链接。这三件事加起来不到十分钟,受益的是每一个用键盘和读屏的人。
至于 SEO——语义标签确实会进搜索引擎的结构化分析,但那部分收益既测不出也控不住。我现在的判断标准很朴素:这个标签在无障碍树里和 div 有没有区别?没有区别就别用它来”表达语义”。