HTML:可访问性的良好基础
通过始终确保将正确的超文本标记语言元素用于正确的目的,可以使大量 Web 内容具有可访问性。本文详细介绍了如何使用 HTML 确保最大程度的可访问性。
预备知识 | 熟悉 HTML、CSS 以及对可访问性概念的基本理解。 |
---|---|
学习成果 |
|
HTML 和可访问性
随着您对 HTML 了解得更多——阅读更多资源,查看更多示例等等——您会不断看到一个共同的主题:使用语义化 HTML 的重要性(有时称为 POSH,即 Plain Old Semantic HTML)。这意味着尽可能将正确的 HTML 元素用于其预期目的。
您可能想知道为什么这如此重要。毕竟,您可以使用 CSS 和 JavaScript 的组合来使几乎任何 HTML 元素以您想要的任何方式运行。例如,您网站上播放视频的控制按钮可以这样标记:
<div>Play video</div>
但是,正如您稍后将更详细地看到的那样,为工作使用正确的元素是有意义的。
<button>Play video</button>
HTML <button>
不仅默认应用了一些合适的样式(您可能需要覆盖),它们还内置了键盘可访问性——用户可以使用 Tab 键在按钮之间导航,并使用 Space、Return 或 Enter 激活他们的选择。
如果您从项目一开始就始终如一地编写语义化 HTML,那么它不会比非语义化(糟糕的)标记花费更多的时间。更棒的是,语义化标记除了可访问性之外还有其他好处:
- 更易于开发——如上所述,您可以免费获得一些功能,而且它更容易理解。
- 在移动设备上更好——语义化 HTML 在文件大小上可能比非语义化意大利面条代码更轻,并且更容易实现响应式。
- 有利于 SEO——搜索引擎对标题、链接等内部的关键字比对非语义化
<div>
等内部的关键字更重视,因此您的文档将更容易被客户找到。
让我们继续更详细地了解可访问的 HTML。
良好的语义
我们已经讨论了正确语义的重要性,以及为什么我们应该为工作使用正确的 HTML 元素。这不能忽视,因为如果处理不当,它是可访问性严重受损的主要地方之一。
在网络上,事实是人们对 HTML 标记做了很多奇怪的事情。通常,滥用 HTML 是由于尚未消失的遗留实践,但有时是因为作者不知道更好的方法。无论如何,您都应该在静态 HTML 页面以及来自服务器端代码或 客户端 JavaScript 框架(例如 React)的动态生成的 HTML 中,尽可能用良好的语义标记替换糟糕的代码。
有时您无法摆脱糟糕的标记——您的页面可能依赖于您无法控制的服务器端代码或 Web/框架组件,或者您的页面上可能有第三方内容(例如广告横幅)。
目标不是“全有或全无”;您所做的每一次改进都将有助于可访问性事业。
使用结构良好的文本内容
屏幕阅读器用户可以拥有的最佳可访问性辅助工具之一是具有标题、段落、列表等的出色文本结构。一个好的语义示例可能如下所示:
<h1>My heading</h1>
<p>This is the first section of my document.</p>
<p>I'll add another paragraph here too.</p>
<ol>
<li>Here is</li>
<li>a list for</li>
<li>you to read</li>
</ol>
<h2>My subheading</h2>
<p>
This is the first subsection of my document. I'd love people to be able to
find this content!
</p>
<h2>My 2nd subheading</h2>
<p>
This is the second subsection of my content, which I think is more interesting
than the last one.
</p>
我们为您准备了一个带有较长文本的版本,供您使用屏幕阅读器试用(请参阅 good-semantics.html)。如果您尝试浏览此内容,您会发现它非常易于导航:
- 当您浏览内容时,屏幕阅读器会读出每个标题,通知您什么是标题,什么是段落等。
- 它在每个元素之后停止,让您以自己舒适的速度进行操作。
- 在许多屏幕阅读器中,您可以跳转到下一个/上一个标题。
- 您还可以在许多屏幕阅读器中调出所有标题的列表,从而将其用作方便的目录来查找特定内容。
人们有时会使用换行符和纯粹用于样式目的的 HTML 元素来编写标题、段落等,例如:
<span style="font-size: 3em">My heading</span> <br /><br />
This is the first section of my document.
<br /><br />
I'll add another paragraph here too.
<br /><br />
1. Here is
<br /><br />
2. a list for
<br /><br />
3. you to read
<br /><br />
<span style="font-size: 2.5em">My subheading</span>
<br /><br />
This is the first subsection of my document. I'd love people to be able to find
this content!
<br /><br />
<span style="font-size: 2.5em">My 2nd subheading</span>
<br /><br />
This is the second subsection of my content. I think is more interesting than
the last one.
如果您使用屏幕阅读器试用我们的较长版本(请参阅 bad-semantics.html),您将不会有很好的体验——屏幕阅读器没有任何东西可以用作路标,因此您无法检索有用的目录,并且整个页面被视为一个巨大的块,因此它只是被一次性读出。
除了可访问性之外,还有其他问题——例如,使用 CSS 样式内容或使用 JavaScript 操作内容更困难,因为没有元素可以用作选择器。
使用清晰的语言
您使用的语言也会影响可访问性。一般来说,您应该使用清晰的语言,不要过于复杂,不要使用不必要的行话或俚语。这不仅有利于认知或其他残疾人士;它也有利于那些母语不是文本语言的读者、年轻人……实际上是每个人!除此之外,您还应该尽量避免使用屏幕阅读器无法清晰朗读的语言和字符。例如:
- 如果可以避免,请不要使用破折号。不要写 5-7,而是写 5 到 7。
- 展开缩写——不要写 Jan,而是写 January。
- 展开首字母缩略词,至少一两次,然后使用
<abbr>
标签来描述它们。
逻辑地组织页面部分
您应该使用适当的分区元素来组织您的网页,例如导航 (<nav>
)、页脚 (<footer>
) 和重复内容单元 (<article>
)。这些为屏幕阅读器(和其他工具)提供了额外的语义,以为用户提供有关他们正在导航的内容的额外线索。
例如,现代内容结构可能如下所示:
<header>
<h1>Header</h1>
</header>
<nav>
<!-- main navigation in here -->
</nav>
<!-- Here is our page's main content -->
<main>
<!-- It contains an article -->
<article>
<h2>Article heading</h2>
<!-- article content in here -->
</article>
<aside>
<h2>Related</h2>
<!-- aside content in here -->
</aside>
</main>
<!-- And here is our main footer that is used across all the pages of our website -->
<footer>
<!-- footer content in here -->
</footer>
您可以在此处找到完整示例。
除了拥有良好的语义和吸引人的布局之外,您的内容还应该在源顺序上具有逻辑意义——您总是可以在以后使用 CSS 将其放置在您想要的位置,但您应该首先正确设置源顺序,这样屏幕阅读器用户所读到的内容才有意义。
尽可能使用语义化的 UI 控件
UI 控件指的是用户与之交互的 Web 文档的主要部分——最常见的是按钮、链接和表单控件。在本节中,我们将介绍创建此类控件时需要注意的基本可访问性问题。关于 WAI-ARIA 和多媒体的后续文章将探讨 UI 可访问性的其他方面。
UI 控件可访问性的一个关键方面是,默认情况下,浏览器允许它们通过键盘进行操作。您可以使用我们的 native-keyboard-accessibility.html 示例进行尝试(请参阅源代码)。在新标签页中打开它,然后尝试按 Tab 键;按下几次后,您应该会看到 Tab 焦点开始在不同的可聚焦元素之间移动。在每个浏览器中,聚焦的元素都有一个突出显示的默认样式(不同浏览器之间略有不同),这样您就可以判断哪个元素被聚焦。
注意:您可以在开发者工具中启用一个叠加层,显示页面 Tab 顺序。更多信息请参阅:辅助功能检查器 > 显示网页 Tab 顺序。
然后您可以按 Enter/Return 键以跟随聚焦的链接或按下按钮(我们包含了一些 JavaScript 来使按钮弹出消息),或者开始键入以在文本输入中输入文本。其他表单元素具有不同的控件;例如,<select>
元素可以使用向上和向下箭头键显示和循环其选项。
您基本上免费获得了这种行为,只需使用适当的元素,例如:
<h1>Links</h1>
<p>This is a link to <a href="https://www.mozilla.org">Mozilla</a>.</p>
<p>
Another link, to the
<a href="https://mdn.org.cn">Mozilla Developer Network</a>.
</p>
<h2>Buttons</h2>
<p>
<button data-message="This is from the first button">Click me!</button>
<button data-message="This is from the second button">Click me too!</button>
<button data-message="This is from the third button">And me!</button>
</p>
<h2>Form</h2>
<form>
<div>
<label for="name">Fill in your name:</label>
<input type="text" id="name" name="name" />
</div>
<div>
<label for="age">Enter your age:</label>
<input type="text" id="age" name="age" />
</div>
<div>
<label for="mood">Choose your mood:</label>
<select id="mood" name="mood">
<option>Happy</option>
<option>Sad</option>
<option>Angry</option>
<option>Worried</option>
</select>
</div>
</form>
这意味着正确使用链接、按钮、表单元素和标签(包括表单控件的 <label>
元素)。
然而,这又是人们有时对 HTML 做奇怪事情的另一个案例。例如,您有时会看到使用 <div>
标记的按钮,例如:
<div data-message="This is from the first button">Click me!</div>
<div data-message="This is from the second button">Click me too!</div>
<div data-message="This is from the third button">And me!</div>
但不建议使用此类代码——您会立即失去本应通过使用 <button>
元素获得的原生键盘可访问性,而且您也无法获得按钮的任何默认 CSS 样式。在极少数甚至不存在的情况下,如果您需要将非按钮元素用作按钮,请使用 button
角色并实现所有默认按钮行为,包括键盘和鼠标按钮支持。
重新构建键盘可访问性
重新添加这些优势需要一些工作(您可以在我们的 fake-div-buttons.html 示例中看到一个示例——另请参阅源代码)。在这里,我们通过给每个假 <div>
按钮属性 tabindex="0"
,使它们能够被聚焦(包括通过 tab 键)。我们还包含了 role="button"
,以便屏幕阅读器用户知道他们可以聚焦并与该元素交互:
<div data-message="This is from the first button" tabindex="0" role="button">
Click me!
</div>
<div data-message="This is from the second button" tabindex="0" role="button">
Click me too!
</div>
<div data-message="This is from the third button" tabindex="0" role="button">
And me!
</div>
基本上,tabindex
属性主要用于允许可选项元素具有自定义的 Tab 顺序(以正数值顺序指定),而不是仅仅按照其默认源顺序进行 Tab 切换。这几乎总是一个坏主意,因为它可能导致严重的混乱。仅在您确实需要时使用它,例如,如果布局以与源代码非常不同的视觉顺序显示事物,并且您希望使事物工作得更合乎逻辑。tabindex
还有另外两个选项:
tabindex="0"
——如上所示,此值允许通常不可选的元素变得可选项。这是tabindex
最有用的值。tabindex="-1"
——这允许通常不可选的元素以编程方式接收焦点,例如,通过 JavaScript,或作为链接的目标。
虽然上述添加允许我们 Tab 到按钮,但它不允许我们通过 Enter/Return 键激活它们。为此,我们必须添加以下 JavaScript 代码:
document.onkeydown = (e) => {
// The Enter/Return key
if (e.key === "Enter") {
document.activeElement.click();
}
};
在这里,我们向 `document` 对象添加了一个监听器,以检测何时在键盘上按下了按钮。我们通过事件对象的 key
属性检查按下了哪个按钮;如果按下的键是 Enter/Return,我们使用 `document.activeElement.click()` 运行存储在按钮 `onclick` 处理程序中的函数。activeElement
为我们提供了当前页面上聚焦的元素。
重新构建功能会带来很多额外的麻烦。而且肯定还会有其他问题。最好一开始就为正确的工作使用正确的元素。
使用有意义的文本标签
UI 控件文本标签对所有用户都非常有用,但正确使用它们对残障用户尤其重要。
您应该确保您的按钮和链接文本标签易于理解且具有区分性。不要仅仅将“点击此处”用作您的标签,因为屏幕阅读器用户有时会列出按钮和表单控件。以下截图显示了 Mac 上的 VoiceOver 列出了我们的控件。
确保您的标签在脱离上下文、单独阅读以及在它们所在的段落上下文中都有意义。例如,以下显示了一个好的链接文本示例:
<p>
Whales are really awesome creatures.
<a href="whales.html">Find out more about whales</a>.
</p>
但这并不是好的链接文本:
<p>
Whales are really awesome creatures. To find out more about whales,
<a href="whales.html">click here</a>.
</p>
注意:您可以在我们的创建链接文章中找到更多关于链接实现和最佳实践的信息。您还可以在good-links.html和bad-links.html中看到一些好的和坏的示例。
表单标签也很重要,可以提示您需要在每个表单输入中输入什么。以下似乎是一个足够合理的示例:
Fill in your name: <input type="text" id="name" name="name" />
然而,这对残障用户来说并不那么有用。上面的示例中没有任何内容可以明确地将标签与表单输入关联起来,并使其清晰地说明如果您看不到它如何填写。如果您使用某些屏幕阅读器访问此内容,您可能只会得到类似“编辑文本”的描述。
以下是一个更好的例子:
<div>
<label for="name">Fill in your name:</label>
<input type="text" id="name" name="name" />
</div>
有了这样的代码,标签将与输入清晰关联;描述将更像“填写您的姓名:编辑文本”。
另外一个好处是,在大多数浏览器中,将标签与表单输入关联意味着您可以单击标签来选择或激活表单元素。这为输入提供了一个更大的点击区域,使其更容易选择。
注意:您可以在 good-form.html 和 bad-form.html 中查看一些好的和坏的表单示例。
您可以在以下视频中找到关于正确文本标签重要性以及如何使用 Firefox 可访问性检查器调查文本标签问题的精彩解释:
可访问的数据表
基本数据表可以使用非常简单的标记编写,例如:
<table>
<tr>
<td>Name</td>
<td>Age</td>
<td>Pronouns</td>
</tr>
<tr>
<td>Gabriel</td>
<td>13</td>
<td>he/him</td>
</tr>
<tr>
<td>Elva</td>
<td>8</td>
<td>she/her</td>
</tr>
<tr>
<td>Freida</td>
<td>5</td>
<td>she/her</td>
</tr>
</table>
但这存在问题——屏幕阅读器用户无法将行或列关联起来作为数据分组。要做到这一点,您需要知道标题行是什么,以及它们是行、列等的标题。对于上面的表格,这只能通过视觉方式完成(请参阅 bad-table.html 并亲自尝试示例)。
现在看看我们的朋克乐队表格示例——您会看到一些可访问性辅助工具在这里发挥作用:
- 表头是使用
<th>
元素定义的——您还可以使用scope
属性指定它们是行或列的标题。这为您提供了完整的数据组,屏幕阅读器可以将其作为单个单元进行消费。 <caption>
元素和<table>
元素的summary
属性都做着类似的工作——它们充当表格的 alt 文本,为屏幕阅读器用户提供表格内容的有用快速摘要。通常首选<caption>
元素,因为它也使其内容可供有视力的用户访问,他们也可能觉得它有用。您实际上不需要两者都用。
注意:有关可访问数据表的更多详细信息,请参阅我们的 HTML 表格可访问性文章。
替代文本
虽然文本内容本身具有可访问性,但多媒体内容却不一定如此——视障人士无法看到图像和视频内容,听障人士无法听到音频内容。我们将在可访问多媒体中详细介绍视频和音频内容,但本文我们将重点介绍不起眼的 <img>
元素的可访问性。
我们编写了一个简单的示例,accessible-image.html,其中包含四张相同的图片:
<img src="dinosaur.png" />
<img
src="dinosaur.png"
alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth." />
<img
src="dinosaur.png"
alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."
title="The Mozilla red dinosaur" />
<img src="dinosaur.png" aria-labelledby="dino-label" />
<p id="dino-label">
The Mozilla red Tyrannosaurus Rex: A two legged dinosaur standing upright like
a human, with small arms, and a large head with lots of sharp teeth.
</p>
第一个图像,当被屏幕阅读器查看时,并没有真正为用户提供太多帮助——例如,VoiceOver 会读出“/dinosaur.png,图像”。它会读出文件名以尝试提供一些帮助。在这个例子中,用户至少会知道这是一种恐龙,但通常文件可能会以机器生成的文件名(例如,来自数码相机)上传,这些文件名很可能无法提供图像内容的上下文。
注意:这就是为什么您不应该在图像中包含文本内容——屏幕阅读器无法访问它。还有其他缺点——您无法选择它并复制/粘贴它。千万不要这样做!
当屏幕阅读器遇到第二张图像时,它会读出完整的 alt 属性——“一只红色的霸王龙:一种两足恐龙,像人类一样直立站立,手臂很小,头部很大,有很多锋利的牙齿。”。
这强调了不仅在使用所谓的alt 文本不可用时使用有意义的文件名,而且还强调了在任何可能的地方在 alt
属性中提供 alt 文本的重要性。
请注意,alt
属性的内容应始终直接表示图像及其视觉传达的内容。alt 应简短、简洁,并包含图像中传达的所有信息,且这些信息未在周围文本中重复。
单个图像的 alt
属性内容因上下文而异。例如,如果 Fluffy 的照片是 Yuckymeat 狗粮评论旁边的头像,则 alt="Fluffy"
是合适的。如果照片是 Fluffy 在动物救助协会的领养页面的一部分,则应包含图像中传达的与潜在狗父母相关且未在周围文本中重复的信息。更长的描述,例如 alt="Fluffy,一只毛很短的三色梗,嘴里叼着一个网球。"
是合适的。由于周围文本可能包含 Fluffy 的大小和品种,因此未包含在 alt
中。然而,由于狗的传记可能不包括毛发长度、颜色或玩具偏好,而潜在父母需要知道这些信息,因此将其包含在内。图像是在户外,还是 Fluffy 有一个红色的项圈和蓝色的牵引绳?这对于领养宠物来说并不重要,因此未包含在内。图像传达的所有信息,只要有视力的用户可以访问并且与上下文相关,都需要传达;仅此而已。保持简短、精确和有用。
不应在此处包含任何个人知识或额外描述,因为它对以前未见过图像的人没有用。如果球是 Fluffy 最喜欢的玩具,或者有视力的用户无法从图像中得知这一点,则不要包含它。
需要考虑的一点是,您的图片在您的内容中是否有意义,或者它们是否纯粹用于视觉装饰,因此没有意义。如果它们是装饰性的,最好将 alt
属性的值写为空文本(请参阅 空 alt 属性),或者只是将它们作为 CSS 背景图片包含在页面中。
如果您确实想提供额外的上下文信息,您应该将其放在图像周围的文本中,或者放在 title
属性中,如上所示。在这种情况下,大多数屏幕阅读器将读出 alt 文本、title 属性和文件名。此外,当鼠标悬停时,浏览器会将 title 文本显示为工具提示。
让我们再快速看看第四种方法:
<img src="dinosaur.png" aria-labelledby="dino-label" />
<p id="dino-label">The Mozilla red Tyrannosaurus…</p>
在这种情况下,我们根本没有使用 alt
属性——相反,我们将图像的描述作为常规文本段落呈现,给它一个 id
,然后使用 aria-labelledby
属性引用该 id
,这使得屏幕阅读器将该段落用作该图像的 alt 文本/标签。如果您想将相同的文本用作多个图像的标签——而 alt
无法做到这一点——这尤其有用。
注意:aria-labelledby
是 WAI-ARIA 规范的一部分,它允许开发人员在需要时为其标记添加额外的语义以改进屏幕阅读器可访问性。
图和图标题
HTML 包含两个元素——<figure>
和 <figcaption>
——它们将某种图形(可以是任何东西,不一定是图像)与图标题关联起来:
<figure>
<img
src="dinosaur.png"
alt="The Mozilla Tyrannosaurus"
aria-describedby="dinodescr" />
<figcaption id="dinodescr">
A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a
human, with small arms, and a large head with lots of sharp teeth.
</figcaption>
</figure>
虽然屏幕阅读器对将图标题与其图形关联的支持存在差异,但如果不存在关联,则包含 aria-labelledby
或 aria-describedby
会创建该关联。话虽如此,元素结构对于 CSS 样式很有用,此外它还提供了一种在源代码中将图像描述放在其旁边的方法。
空的 alt 属性
<h3>
<img src="article-icon.png" alt="" />
Tyrannosaurus Rex: the king of the dinosaurs
</h3>
有时图像会包含在页面设计中,但其主要目的是视觉装饰。您会在上面的代码示例中注意到图像的 alt
属性为空——这是为了让屏幕阅读器识别图像,但不尝试描述图像(而是它们会说“图像”或类似的话)。
使用空 alt
而不是不包含它的原因是,如果没有提供 alt
,许多屏幕阅读器会宣布整个图像 URL。在上面的示例中,图像充当与其关联的标题的视觉装饰。在这种情况下,以及图像仅是装饰且没有内容价值的情况下,您应该在 img
元素中包含一个空的 alt
。另一种替代方法是使用 aria role
属性 role="presentation"
,因为这也可以阻止屏幕阅读器读出替代文本。
注意:如果可能,您应该使用 CSS 显示仅用于装饰的图像。
关于链接的更多信息
链接(带有 href
属性的 <a>
元素),取决于它们的使用方式,可能会帮助或损害可访问性。默认情况下,链接在外观上是可访问的。它们可以通过帮助用户快速导航到文档的不同部分来提高可访问性。如果它们的无障碍样式被删除,或者 JavaScript 导致它们以意想不到的方式行为,它们也可能会损害可访问性。
链接样式
默认情况下,链接在颜色和文本装饰方面与其他文本在视觉上有所不同,链接默认为蓝色并带下划线,访问后为紫色并带下划线,并在获得键盘焦点时带有焦点环。
颜色不应作为区分链接和非链接内容的唯一方法。链接文本颜色,与所有文本一样,必须与背景颜色有显著差异(4.5:1 的对比度)。此外,链接应在视觉上与非链接文本有显著差异,链接文本与周围文本之间以及默认、已访问和焦点/活动状态之间至少有 3:1 的对比度要求,并且所有这些状态颜色与背景颜色之间至少有 4.5:1 的对比度。
onclick
事件
锚标签经常被滥用与 onclick
事件结合使用,通过将 href 设置为 "#"
或 "javascript:void(0)"
来创建伪按钮,以防止页面刷新。
这些值在复制或拖动链接、在新标签页或窗口中打开链接、收藏夹以及 JavaScript 仍在下载、出错或被禁用时会导致意外行为。这还会向辅助技术(例如屏幕阅读器)传达不正确的语义。在这些情况下,建议改用 <button>
。通常,您应该只使用带有正确 URL 的锚点进行导航。
外部链接和链接到非 HTML 资源
通过 target="_blank"
声明在新标签页或窗口中打开的链接,以及 href
值指向文件资源的链接,应包含一个指示符,说明激活链接时将发生的行为。
有低视力障碍、借助屏幕阅读技术导航或有认知障碍的人可能会在新标签页、窗口或应用程序意外打开时感到困惑。旧版本的屏幕阅读软件甚至可能不会宣布这种行为。
在新标签页或窗口中打开的链接
<a target="_blank" href="https://www.wikipedia.org/"
>Wikipedia (opens in a new window)</a
>
链接到非 HTML 资源
<a target="_blank" href="2017-annual-report.ppt"
>2017 Annual Report (PowerPoint)</a
>
如果使用图标代替文本来表示此类链接行为,请确保它包含替代描述。
跳过链接
跳过链接,也称为 skipnav,是一个 a
元素,放置在尽可能靠近开头的 <body>
元素的位置,链接到页面主要内容的开头。此链接允许人们绕过网站多个页面中重复的内容,例如网站的标题和主导航。
跳过链接对于借助辅助技术(如开关控制、语音命令或口棒/头杖)进行导航的人特别有用,因为通过重复链接移动可能是一项费力的任务。
临近度
大量交互式内容(包括锚点)如果彼此在视觉上非常接近,则应插入空格以将其分隔。这种间隔对于患有精细运动控制问题的人是有益的,他们可能在导航时意外激活错误的交互式内容。
可以使用 CSS 属性(例如 margin
)创建间距。
总结
现在,您应该已经非常熟悉在大多数情况下编写可访问的 HTML。在下一篇文章中,我们将为您提供一些测试,您可以使用它们来检查您对所有这些信息的理解和掌握程度。