LabHub
学习 学习路径 课程

HTML — 一个标签顶一项功能

用 div 做的按钮丢掉的七样东西

在 LabHub 中继续学习

一句话总结

如果不使用 <button> 而改用 <div onclick>,就会失去浏览器原本代为完成的七项工作,而人们通常不会重新实现其中五项。

概念图: 失去浏览器原本代为完成的七项工作 · 只使用键盘的用户 · 选择标签时就应作出的判断 · 无法通过 Tab 到达

问题为何出现——看不见的用户

如果用鼠标开发,再用鼠标验证,这类事故始终不会暴露,因为 <div onclick> 在鼠标操作下表现得非常完美。QA 也用鼠标检查,所以它会直接上线。

真正受影响的是只使用键盘的用户。他们可能手腕受伤,可能使用屏幕阅读器,也可能只是觉得 Tab 更快。对这些用户而言,那个按钮虽然显示在屏幕上,却只是一张无法点击的图片。如果它是支付按钮,他们就无法完成支付。

修复成本也会随着时间增加。工作不再只是更换一个标签,还要沿着它上方累积的 CSS 选择器、事件委托和测试选择器逐一修改。因此,本文讨论的不是“以后再处理的清单”,而是选择标签时就应作出的判断

会失去什么

<div onclick="save()">저장</div> 会失去以下能力。

  1. 无法通过 Tab 到达——需要 tabindex="0"
  2. 无法通过 Enter 或 Space 激活——必须自行绑定键盘处理器。
  3. 屏幕阅读器不会读作“按钮”——它只是普通文本。
  4. 无法禁用——disabled 不起作用。
  5. 无法提交表单——没有 type="submit"
  6. 没有焦点环——键盘用户不知道当前位置。
  7. 没有浏览器默认行为——包括上下文菜单和自动化工具识别。

只要写下 <button>,这些能力就全部免费获得。可访问性不是之后附加的功能,而是在选择标签时就已经大体决定。

地标——页面地图

屏幕阅读器用户不会从页面顶部开始依次阅读,而会在各个地标之间跳转

<header>  사이트 머리   </header>
<nav>     탐색          </nav>
<main>    본문 — 페이지에 하나만 </main>
<aside>   곁다리        </aside>
<footer>  꼬리          </footer>

存在 <main> 时,“跳到正文”功能才能工作。<div class="main"> 没有任何语义——类名不会向机器传达任何信息。

标题就是目录

h1h6 不是字号,而是文档目录。屏幕阅读器会只浏览标题来理解结构。

因为 h3 看起来漂亮就使用它,是最常见的可访问性问题之一。

alt 不是“说明文字”

alt图片消失时用来填补其位置的文本

图片 alt
产品照片 alt="빨간 등산 배낭 45L"
链接内的徽标 alt="홈으로"——描述的不是图片,而是链接目的
装饰性分隔线 alt=""——应当留空
旁边已有相同说明的图片 alt=""——重复朗读会造成干扰

省略 alt 属性本身与写成 alt="" 并不相同。省略后,屏幕阅读器会朗读文件名(IMG_20240103.jpg);留空则会安静跳过。装饰图片必须明确写出 alt=""

没有标签的输入框就没有名称

<!-- ❌ placeholder 는 라벨이 아니다 -->
<input placeholder="이메일">

<!-- ✅ -->
<label for="email">이메일</label>
<input id="email" type="email" autocomplete="email">

placeholder 会在输入后消失,用户将无法确认这个输入框原本要求填写什么。对于低视力用户,它的对比度也不足。

关联标签后,点击文字也会让输入框获得焦点,这在移动设备上尤其重要。

另外,正确设置 typeautocomplete 后,移动键盘会随之改变,自动填充也能工作,例如 type="email"type="tel"autocomplete="one-time-code"

链接与按钮不同

链接用于跳转,按钮用于执行操作。

<a href="#" onclick="..."> 两者都不是。此外,链接文本本身必须说明目的。屏幕阅读器用户会抽取所有链接并以列表查看,如果列表中只有二十个“这里”和“查看更多”,就毫无用处。

表格必须有表头单元格

<table>
  <caption>월별 매출</caption>
  <thead><tr><th scope="col">월</th><th scope="col">매출</th></tr></thead>
  <tbody><tr><th scope="row">1월</th><td>1,200</td></tr></tbody>
</table>

只有设置 scope,屏幕阅读器才会读成“1 月、销售额、1200”。否则只会连续朗读数字。

不要用表格实现布局。 那是 CSS Grid 的职责。

不要遗漏 lang

<html lang="ko">

缺少它时,屏幕阅读器会按照英语发音规则朗读韩语。这是仅修改一个字符就能取得巨大效果的改进之一。

ARIA 是最后手段

错误的 ARIA 还不如没有 ARIA。

即使添加 role="button",也不会自动获得键盘操作。它只改变了表面名称,实际行为完全不变。因此规则只有一条。

如果存在合适的 HTML 元素,就使用它。 只有 HTML 没有对应元素时,例如标签页、树或实时区域,才使用 ARIA。

如何在实际工作中检查

自动检查工具只能发现30~40% 的问题,因为它只能检查对比度不足、缺少 alt机器能够观察的问题。其余部分必须由人检查。

这三项比自动工具能发现更多问题。

实际工作中,最好把它固化为 PR 检查清单中的一行,这样更容易长期坚持。只需问一句:“新建的交互元素是否只用键盘操作过?”期待人们每次都靠记忆遵守的规则,最终一定会被遗漏。