TT Lab
开始
学习 学习路径 课程

HTML — 一个标签顶一项功能

没有名字的输入框等于不存在

在 TT Lab 中继续学习

一句话总结

表单控件的可访问名称(accessible name)并不取决于标记中有没有 label 这几个字,而是按照既定顺序计算出来的结果。不了解这套计算,就会写满了 label,却依然做出没有名称的输入框。

为什么需要它

在注册表单上,人们卡住的地方总是一样的:点了提交,却什么都没有发生。屏幕上某处大概变红了,但屏幕阅读器用户什么声音也没听到,键盘用户的焦点则还停在按钮上。

这时打开标记来看,label 有,required 也有。可是 for="mail",而输入框是 id="email"。用眼睛看它们紧挨在一起,没有人会发现问题。对机器来说,这两者毫无关系,这个输入框的名称是没有。

对于没有名称的输入框,屏幕阅读器只会读作“编辑”。根本无从知道这是要填什么的输入框。而且这种缺陷常常被自动检查工具以“存在 label 元素”为由放行,所以能存活很久。

工作原理

HTML-AAM 为每种控件规定了求名称的顺序。输入文字的输入框和 textarea 是这样的:

1. aria-labelledby  — 가리킨 요소들의 글자를 이어 붙인다
2. aria-label       — 속성값 그대로
3. 연결된 label      — for/id 또는 감싼 label 의 글자
4. title            — 마우스를 올려야 보이는 그것
5. placeholder      — 글자를 치면 사라지는 그것

原始出处是 HTML Accessibility API Mappings 第 4.1 节 和 Accessible Name and Description Computation。

该代码块中的韩文说明依次为:aria-labelledby 是把所指向元素的文字拼接起来;aria-label 直接取属性值;关联的 label 取 for/id 关联或包裹它的 label 的文字;title 是必须把鼠标悬停才能看到的那个;placeholder 是一输入文字就消失的那个。

这里有两点很重要。

第一,只要前面的某一步给出了值,后面的就不再看了。 所以只要加上 aria-label="이메일"(韩文,意为“邮箱”),不管屏幕上可见的 label 文字是什么,屏幕阅读器都只读 aria-label。屏幕上写的是“公司邮箱”,语音却说“邮箱”,这种界面就是这样产生的。用语音操作的用户会念出看到的文字,所以这种错位对他们来说是根本无法操作的问题。

第二,placeholder 也确实能成为名称。 所以检查工具不会把它判为“没有名称”。但这个名称在输入文字的那一刻就消失了,在长表单里回头查看时,就无从确认这是在填什么的输入框。对低视力用户来说,对比度也不够。

分组需要分组的名称

单选按钮的每一个并不是答案,而是多个合在一起构成一个问题。即使给每个选项都加上 label,也只能读到“邮箱单选按钮,已选中”。正在选择的到底是什么,哪里都没有。

用 fieldset 把它们包起来并加上 legend,这个分组就有了名称。这样就会像“接收通知的方式,邮箱单选按钮”一样,把问题和答案一起读出来。

错误不是颜色

红色边框对分辨不出颜色的人毫无意义,对不看屏幕的人则根本不存在。需要另外提供程序能够读取的信号。

aria-describedby 可以用空格列出多个 id。所以同时指向帮助说明和错误消息,即使出现错误,像“至少十二个字符”这样的规则说明也不会消失。出错时把规则删掉的实现,出乎意料地常见。

在现场相遇的样子

WCAG 的 Labels or Instructions 只说了一句“需要输入时,请提供标签或说明”。在实际工作中,这一句被破坏的方式大致有三种。

  1. 为了设计好看而删掉 label,只留下 placeholder
  2. 复用组件时把 id 写死成固定值,在一个页面上用两次,id 就重复了。一旦重复,后面的 label 就会指向前面的输入框
  3. 把错误消息用 aria-describedby 替换进去,导致规则说明消失

这三种情况用鼠标检查时都完好无损。所以本课程从运行检查器、用眼睛确认名称是从哪里来的开始。如果来源是 label,就是安全的;如果是 placeholder 或 title,就是会消失的名称;如果是空的,这个输入框就是不存在的输入框。

另外,正确设置 autocomplete 也属于可访问性。对于手部操作困难的人来说,打字的次数就是成本,而 HTML 标准的 autofill 字段名称 中没有的值,浏览器会直接忽略。autocomplete="e-mail" 什么作用也没有。

下一项实验要做什么

编写一个注册表单,并用计算器确认每个输入框的名称来自哪里。把来自 placeholder 的名称改成 label,把单选按钮用 fieldset 分组,并让程序能够读取错误。最后把计算器的结果保存为文件。