section 和 div 的差别在无障碍树里,不在源码里

语义化标签的常见说法是”有利于 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 有没有区别?没有区别就别用它来”表达语义”。

← 返回技术笔记