很多人写网页的时候,习惯用一层层的 div 把内容包起来,再给它们加各种 class 来调整样式。在普通浏览器里看起来整整齐齐,但屏幕阅读器用户听到的却是另一回事。屏幕阅读器是一种把屏幕内容朗读出来的软件,用户全靠耳朵来理解页面。如果页面上只有一堆 div 和 span,它根本分不清哪里是导航,哪里是正文,哪里是按钮。结果用户可能听上几十秒,也搞不清该怎么下单、怎么登录。要改变这种情况,靠的就是语义化 HTML。

一、屏幕阅读器是怎么“看”网页的

屏幕阅读器没有办法像我们一样一眼扫过整个页面。它会把网页里的代码按照从上到下的顺序读出来,同时用语音提示“这是什么”。比如看到一个真正的标题,它会说“标题,一级标题”;看到一个链接,它会说“链接”;遇到一个按钮,它会说“按钮”。这样一来,用户就可以通过听来判断页面的结构。

1.1 屏幕阅读器的基本工作方式

屏幕阅读器在朗读时,靠的是网页里的标签。标签就像给网页内容贴的“身份牌”。我们平时用的 div 和 span 在屏幕上没有任何区别,在代码里也只是普通的容器。屏幕阅读器读到 div 的时候,只会机械地说“div”,没有任何额外的含义。所以如果你把一个导航菜单做成 div 加 span,屏幕阅读器就只能念出一长串文字,用户根本不知道这串文字是导航,也不知道可以按快捷键直接跳过去。

1.2 为什么语义化对屏幕阅读器那么重要

语义化标签能让屏幕阅读器在朗读时给出更多提示。比如用 nav 标签包起来的区域,屏幕阅读器会告诉用户“这是导航”,用户就可以选择跳过或者快速进入。用 main 标签包起来的区域,屏幕阅读器会提示“这是主要内容”,用户可以直接到达正文。这就像你在房间里贴了门牌,第一次来的人也能很快找到厨房和卧室。如果没有门牌,只能在每个房间门口探头看。

二、最常用的语义化标签

语义化标签并不复杂,它是 HTML 里本来就有的东西,只不过以前经常被我们忽略。下面从最常用的几个说起。

2.1 头部和底部:header 与 footer

header 通常放网站的标题、logo、搜索框这些“开头信息”。footer 通常放版权、联系方式、一些辅助链接。屏幕阅读器用户可以通过快捷键快速跳到页头或页尾,不用从头到尾听一遍。

<!-- 技术栈:HTML -->
<!-- 网站头部与底部 -->
<header>
  <h1>老王的小卖部</h1>
  <p>零食、饮料、日常用品,都在这里</p>
</header>

<footer>
  <p>© 2025 老王的小卖部 · 地址:幸福街1号</p>
</footer>

2.2 导航:nav

nav 用来标记一组主要的导航链接。把链接列表放进 nav 里,屏幕阅读器会明确说出“这是导航”。如果你只放一个 div,它不会这样说。导航里最好再配合一个清晰的标签,比如 aria-label,让用户知道这个导航是关于什么的。

<!-- 技术栈:HTML -->
<!-- 主导航 -->
<nav aria-label="主导航">
  <ul>
    <li><a href="/">首页</a></li>
    <li><a href="/products">商品</a></li>
    <li><a href="/about">关于我们</a></li>
  </ul>
</nav>

2.3 内容主体:main、article、section

main 表示页面最核心的、独有的一块内容。一个页面只用一个 main,屏幕阅读器用户可以通过快捷键直接跳到主要部分。article 表示一篇完整文章、一条帖子或一个独立模块。section 表示一个主题分组,比如“本周促销”“新品推荐”。这三个标签配合起来,页面的层次就非常清楚。

<!-- 技术栈:HTML -->
<!-- 主体区域 -->
<main>
  <article>
    <h2>今天店里来了新货</h2>
    <p>新到的辣条和汽水,欢迎来试吃。</p>
  </article>
  <section>
    <h3>本周促销</h3>
    <p>满20元减5元,仅限周末。</p>
  </section>
</main>

2.4 侧边栏:aside

aside 用来放与主内容相关性不强的补充信息,比如广告、相关推荐、店铺位置。屏幕阅读器会把 aside 当作次要内容处理,不会让用户以为这也是正文的一部分。

<!-- 技术栈:HTML -->
<!-- 侧边栏 -->
<aside>
  <h2>店铺位置</h2>
  <p>幸福街1号,靠近公交站。</p>
</aside>

2.5 标题层级 h1 到 h6

屏幕阅读器用户最喜欢用标题来导航。他们按一个快捷键,屏幕阅读器就会跳到下一个标题。所以标题的顺序和层级特别重要。一个页面通常只有一个 h1,然后按层级往下排 h2、h3,不要从 h2 直接跳成 h5,也不要为了视觉效果把 h3 当成 h1 来用。

<!-- 技术栈:HTML -->
<!-- 清晰的标题层级 -->
<h1>老王的小卖部</h1>
<h2>商品分类</h2>
<h3>零食区</h3>
<h3>饮料区</h3>
<h2>促销活动</h2>

三、让表单和图片也能被“听见”

表单和图片是屏幕阅读器用户经常遇到困难的地方。如果处理不好,用户可能压根不知道输入框该填什么,也不知道一张图片表达了什么内容。

3.1 表单控件的 label

表单里的输入框如果没有对应的 label,屏幕阅读器只能念“输入框”,用户不知道这里该填用户名还是手机号。把 label 的 for 属性指向输入框的 id,就能把提示文字和输入框绑在一起。这样屏幕阅读器聚焦到输入框时,会先念出 label 里的文字。

<!-- 技术栈:HTML -->
<!-- 表单输入框与 label 关联 -->
<form>
  <label for="username">用户名</label>
  <input type="text" id="username" name="username">

  <label for="password">密码</label>
  <input type="password" id="password" name="password">

  <button type="submit">登录</button>
</form>

3.2 图片的 alt

图片上的信息对视力正常的用户一目了然,但屏幕阅读器用户只能听到 alt 属性里的文字。如果这张图片是商品图,alt 就写清楚商品名和特点。如果图片只是装饰用的分割线、背景图,alt 就写成空字符串,让屏幕阅读器直接跳过,避免读出一堆乱七八糟的结果。

<!-- 技术栈:HTML -->
<!-- 有意义的图片 alt -->
<img src="product-cola.jpg" alt="一瓶红色包装的可乐">

<!-- 装饰图使用空 alt -->
<img src="decorative-line.jpg" alt="">

四、屏幕阅读器专属的“辅助工具”:ARIA

ARIA 是一套专门用来增强网页可访问性的 HTML 属性。它不是要替代原生语义化标签,而是在原生标签表达不了的时候来补充信息。注意,如果原生 HTML 已经能表达意思,就不要用 ARIA,否则反而会让屏幕阅读器用户更混乱。

4.1 什么时候用 ARIA

当我们想自己做一个开关、菜单、弹窗时,原生标签不一定能表达“这个开关现在是开还是关”。这时可以加上 role 和 aria-checked 这类属性,让屏幕阅读器能理解自定义控件。

<!-- 技术栈:HTML -->
<!-- 自定义开关,用 ARIA 表达状态 -->
<button role="switch" aria-checked="true" id="light-switch">
  灯已开
</button>

4.2 状态和动态更新:aria-live

页面上有些内容会动态变化,比如购物车提示“已加入一件商品”,或者聊天窗口弹出新消息。屏幕阅读器默认不会主动朗读这些变化,除非你告诉它。给容器加上 aria-live 后,屏幕阅读器会在内容变化时自动提醒用户。

<!-- 技术栈:HTML -->
<!-- 动态消息区域 -->
<div aria-live="polite">
  正在加载最新商品…
</div>

4.3 错误提示:aria-describedby

表单填写出错时,视觉上我们可以看到红色提示文字,但屏幕阅读器用户需要额外帮助。用 aria-describedby 把输入框和错误提示关联起来,屏幕阅读器在聚焦到输入框时就会读出提示内容。

<!-- 技术栈:HTML -->
<!-- 输入框与错误提示关联 -->
<label for="email">邮箱</label>
<input type="email" id="email" aria-describedby="email-error">
<span id="email-error">请输入正确的邮箱格式,比如 name@example.com</span>

4.4 记住 ARIA 使用原则

ARIA 是好东西,但别滥用。能用 button 就用 button,不要用 div 加 role 来模拟。能用 nav 就用 nav,不要自己写 role="navigation"。原生的标签自带大量无障碍功能,屏幕阅读器对它们最熟悉。ARIA 只是在实在没有原生标签或原生属性不够用的时候才出手。

五、完整示例:一个适配屏幕阅读器的页面结构

把前面提到的东西拼在一起,就是一个比较完整的页面骨架。这个页面没有依赖任何框架,也没有混入 CSS 和 JavaScript,只是用纯 HTML 把结构摆清楚。你可以把这段代码放到浏览器里,打开屏幕阅读器听一听效果。

<!-- 技术栈:HTML -->
<!-- 一个完整的、适配屏幕阅读器的页面结构 -->
<header>
  <h1>老王的小卖部</h1>
  <nav aria-label="主导航">
    <ul>
      <li><a href="/">首页</a></li>
      <li><a href="/products">商品</a></li>
      <li><a href="/about">关于我们</a></li>
    </ul>
  </nav>
</header>

<main>
  <article>
    <h2>今天店里来了新货</h2>
    <p>新到的辣条和汽水,欢迎来试吃。</p>
  </article>

  <section>
    <h3>本周促销</h3>
    <p>满20元减5元,仅限周末。</p>
  </section>

  <section>
    <h2>登录</h2>
    <form>
      <label for="username">用户名</label>
      <input type="text" id="username" name="username">

      <label for="password">密码</label>
      <input type="password" id="password" name="password">

      <button type="submit">登录</button>
    </form>
  </section>
</main>

<aside>
  <h2>店铺位置</h2>
  <p>幸福街1号,靠近公交站。</p>
</aside>

<footer>
  <p>© 2025 老王的小卖部 · 营业时间:8:00-22:00</p>
</footer>

六、应用场景

语义化结构和无障碍优化并不是锦上添花的小事。最典型的应用场景是政府网站、银行、医院这类公共服务平台,它们必须保证所有人群都能正常使用,不然就真的会有人办不了事。电商网站也一样,从商品列表、购物车到结算页,任何一个环节对屏幕阅读器用户不友好,就相当于失去了一部分顾客。内容平台和博客也值得做,因为读者经常要快速浏览标题,屏幕阅读器配合标题导航可以很快找到想读的文章。还有很多企业内部系统,员工可能依赖读屏软件工作,语义化做得好,效率能提升一大截。

七、优点和缺点

语义化 HTML 的优点非常明显。对屏幕阅读器用户来说,网页变得可感知、可操作了。对搜索引擎来说,它也更喜欢结构清晰的页面,因为这些语义标签能让蜘蛛快速理解哪里是重点内容。对开发者自己来说,代码更好读、更好维护,后面接手的人不用翻几十个 div 才能找到正文。

缺点主要是前期需要学习和改变习惯。老项目如果要改造,得花时间把所有 div 替换成对应的语义标签,还可能影响一些页面样式。另外不同屏幕阅读器的表现会有细微差别,测试起来比普通浏览器麻烦一些。不过这些都是可以克服的,用点心就能做好。

八、注意事项

第一,不要用 div 加 onclick 来冒充按钮。真正的按钮应该用 button 标签,这样屏幕阅读器才能告诉用户“这是一个按钮”,也才能支持键盘操作。第二,标题层级不要跳。页面结构要像一本书的目录,层级明显,跳着用会让读屏用户摸不着北。第三,链接文字要有意义,一定要写清楚这个链接指向哪里,不要用“点这里”“更多”这类含糊的词汇。第四,图片的 alt 要根据实际作用来填,信息图写清楚,装饰图写空。第五,所有功能都要能用键盘操作,这是屏幕阅读器用户的基本保障。第六,动态内容比如提示、加载状态一定要配合 aria-live,否则用户等于看不见消息。第七,做完了别忘了用读屏软件自己听一遍,很多问题一听就暴露了。

九、文章总结

语义化 HTML 不是什么高深技术,就是让网页结构回归它本来的样子:header 就说头部,nav 就说导航,main 就说主内容,button 就是按钮,label 就是提示文字。让屏幕阅读器听得懂,本质上就是让网页更通透。我们每个人都不希望自己点不进一个页面,屏幕阅读器用户也一样。把语义化标签用对,把 ARIA 用在真正需要的地方,在写页面时多替听声音的用户想一步,这个网页就真的变好了。