CSS 和 JavaScript 无障碍最佳实践

CSS 和 JavaScript,如果使用得当,也有可能提供无障碍的 Web 体验;如果使用不当,它们可能会严重损害无障碍性。本文概述了一些 CSS 和 JavaScript 的最佳实践,应该加以考虑,以确保即使是复杂的内容也尽可能无障碍。

预备知识 熟悉 HTMLCSS 以及对可访问性概念的基本理解
学习成果
  • 无障碍的文本大小和布局。
  • 颜色对比度。
  • :focus:hover 样式的重要性。
  • 合理的动画使用 — 巧妙地使用动画并提供关闭控件。
  • 隐藏内容以使其不变得无法访问的最佳实践。
  • JavaScript 过多是有问题的,以及非侵入式 JavaScript 的价值。
  • 合理使用事件,这样你就不会锁定特定的控制类型。

CSS 和 JavaScript 无障碍吗?

CSS 和 JavaScript 对无障碍的重要性不如 HTML 那么直接,但它们仍然能够帮助或损害无障碍性,这取决于它们的使用方式。换句话说,重要的是你要考虑一些最佳实践建议,以确保你使用的 CSS 和 JavaScript 不会破坏文档的无障碍性。

CSS

让我们从 CSS 开始。

正确的语义和用户期望

可以使用 CSS 将任何 HTML 元素设计成任何样子,但这并不意味着你应该这样做。正如我们在HTML:无障碍的良好基础一文中经常提到的,你应该尽可能使用适当的语义元素来完成工作。如果你不这样做,可能会给所有人,尤其是残障用户,造成困惑和可用性问题。使用正确的语义与用户期望有很大关系——元素根据其功能以某种方式呈现和行为,这些通用约定是用户所期望的。

例如,如果开发人员没有适当地使用标题元素来标记内容,屏幕阅读器用户就无法通过标题元素导航页面。同样,如果你对标题进行样式设置,使其看起来不像标题,那么标题就会失去其视觉目的。

总而言之,你可以更新页面功能的样式以适应你的设计,但不要更改太多,以至于它不再像预期的那样呈现或行为。以下部分总结了要考虑的主要 HTML 功能。

“标准”文本内容结构

标题、段落、列表 — 页面的核心文本内容

html
<h1>Heading</h1>

<p>Paragraph</p>

<ul>
  <li>My list</li>
  <li>has two items.</li>
</ul>

一些典型的 CSS 可能如下所示

css
h1 {
  font-size: 5rem;
}

p,
li {
  line-height: 1.5;
  font-size: 1.6rem;
}

你应该

  • 选择合适的字体大小、行高、字间距等,使你的文本逻辑、清晰、阅读舒适。
  • 确保你的标题从正文中脱颖而出,通常像默认样式一样又大又粗。你的列表应该看起来像列表。
  • 你的文本颜色应该与背景颜色形成良好的对比。

有关更多信息,请参阅HTML 中的标题和段落以及CSS 文本样式

强调文本

赋予其所包裹文本特定强调的行内标记

html
<p>The water is <em>very hot</em>.</p>

<p>
  Water droplets collecting on surfaces is called <strong>condensation</strong>.
</p>

你可能想为你的强调文本添加一些简单的颜色

css
strong,
em {
  color: #a60000;
}

然而,你很少需要以任何重要方式设置强调元素的样式。粗体和斜体文本的标准约定非常容易识别,改变样式可能会造成混淆。有关强调的更多信息,请参阅强调和重要性

缩写

允许将缩写词、首字母缩略词或首字母与它的完整形式关联起来的元素

html
<p>
  Web content is marked up using Hypertext Markup Language, or
  <abbr>HTML</abbr>.
</p>

同样,你可能想以某种简单的方式设置它的样式

css
abbr {
  color: #a60000;
}

缩写的公认样式约定是虚线underline,显著偏离此约定是不明智的。有关缩写的更多信息,请参阅缩写

超链接 — 你在网络上前往新地方的方式

html
<p>Visit the <a href="https://www.mozilla.org">Mozilla homepage</a>.</p>

下面显示了一些非常简单的链接样式

css
a {
  color: red;
}

a:hover,
a:visited,
a:focus {
  color: #a60000;
  text-decoration: none;
}

a:active {
  color: black;
  background-color: #a60000;
}

标准链接约定是:在标准状态下,带有下划线且颜色不同(默认:蓝色);当链接之前已访问过时,颜色会发生变化(默认:紫色);当链接被激活时,颜色又会发生变化(默认:红色)。此外,当鼠标悬停在链接上时,鼠标指针会变成手形图标,并且当链接被聚焦(例如,通过 Tab 键)或激活时,会收到高亮显示。下图显示了 Firefox(虚线轮廓)和 Chrome(蓝色轮廓)中的高亮显示

Screenshot of a list of links in Firefox browser. The list contains 4 items. The second list item is highlighted using a blue dotted outline when it is focussed via tabbing.

Screenshot of a list of links in Chrome browser. The list contains 4 items. The third list item is highlighted using a blue outline when it is focussed via tabbing.

你可以对链接样式发挥创意,只要你在用户与链接交互时持续提供反馈即可。当状态改变时,肯定会发生一些事情,你不应该取消指针光标或轮廓——两者对于使用键盘控制的用户来说都是非常重要的无障碍辅助工具。

表单元素

允许用户向网站输入数据的元素

html
<div>
  <label for="name">Enter your name</label>
  <input type="text" id="name" name="name" />
</div>

你可以在我们的form-css.html示例中看到一些好的 CSS 示例(也可以在线查看)。

你为表单编写的大部分 CSS 将用于设置元素大小、对齐标签和输入,并使它们看起来整洁。

然而,你不应偏离表单元素在获得焦点时预期的视觉反馈过多,这与链接基本相同(见上文)。你可以为表单焦点/悬停状态设置样式,以使此行为在不同浏览器中更一致或更好地适应你的页面设计,但不要完全取消它——再次强调,人们依赖这些线索来帮助他们了解正在发生什么。

表格

用于呈现表格数据的表格。

你可以在我们的table-css.html示例中看到一个很好的简单表格 HTML 和 CSS 示例(也可以在线查看)。

表格 CSS 通常用于使表格更好地融入你的设计并看起来不那么丑陋。一个好主意是确保表格标题突出显示(通常使用粗体),并使用斑马条纹使不同的行更容易解析。

颜色和颜色对比度

为你的网站选择配色方案时,请确保文本(前景)颜色与背景颜色形成良好的对比。你的设计可能看起来很酷,但如果色盲等视力障碍者无法阅读你的内容,那就毫无意义。

有一种简单的方法可以检查你的对比度是否足够大,不会造成问题。有许多在线对比度检查工具,你可以输入你的前景和背景颜色来检查它们。例如,WebAIM 的颜色对比度检查器使用简单,并提供了你需要遵循 WCAG 颜色对比度标准的解释。

注意:高对比度也能让任何在明亮环境(例如阳光下)使用带有光面屏幕的智能手机或平板电脑的人更好地阅读页面。

另一个提示是不要仅仅依靠颜色来提供路标/信息,因为这对于那些看不到颜色的人来说毫无用处。例如,与其用红色标记必填表单字段,不如用星号和红色标记它们。

隐藏事物

在许多情况下,视觉设计要求并非所有内容都同时显示。例如,在我们的选项卡式信息框示例中(请参阅源代码),我们有三个信息面板,但我们正在将它们定位在彼此之上,并提供可以点击以显示每个面板的选项卡(它也支持键盘访问——你可以选择使用 Tab 和 Enter/Return 键来选择它们)。

Three tab interface with Tab 1 selected and only its contents are displayed. The contents of other tabs are hidden. If a tab is selected, then its text-color changes from black to white and the background-color changes from orange-red to saddle brown.

屏幕阅读器用户并不关心这些——只要源代码顺序合理,并且他们可以访问所有内容,他们就很高兴。绝对定位(如本例所示)通常被认为是隐藏内容以实现视觉效果的最佳机制之一,因为它不会阻止屏幕阅读器访问内容。

另一方面,你不应该使用visibility: hiddendisplay: none,因为它们会向屏幕阅读器隐藏内容。除非,当然,你有充分的理由希望此内容对屏幕阅读器隐藏。

注意:仅针对屏幕阅读器用户的不可见内容提供了围绕此主题的更多有用细节。

接受用户可以覆盖样式

用户可以用自己的自定义样式覆盖你的样式,例如

用户可能出于各种原因这样做。视力受损的用户可能希望在他们访问的所有网站上放大文本,或者严重色盲的用户可能希望将所有网站设置为易于他们查看的高对比度颜色。无论有什么需求,你都应该对此感到满意,并使你的设计足够灵活,以便这些更改在你的设计中也能正常工作。例如,你可能希望确保你的主要内容区域能够处理更大的文本(也许它会开始滚动以允许全部显示),而不仅仅是隐藏它或完全破坏。

JavaScript

JavaScript 也可能破坏可访问性,这取决于它的使用方式。

现代 JavaScript 是一种功能强大的语言,我们现在可以用它做很多事情,从简单的内容和 UI 更新到成熟的 2D 和 3D 游戏。没有规定所有内容都必须对所有人 100% 可访问——你只需要尽力而为,让你的应用程序尽可能无障碍。

简单的内容和功能可以说很容易实现无障碍——例如文本、图像、表格、表单和激活功能的按钮。正如我们在HTML:无障碍的良好基础一文中探讨的那样,关键考虑因素是

  • 良好的语义:为正确的工作使用正确的元素。例如,确保你使用标题和段落,以及<button><a> 元素
  • 确保内容以文本形式提供,无论是直接作为文本内容、表单元素的良好文本标签,还是文本替代项,例如图像的 alt 文本。

我们还研究了一个如何使用 JavaScript 来构建缺失功能的示例——请参阅重新构建键盘可访问性。这不是理想的——实际上你应该为正确的工作使用正确的元素——但它表明在某些情况下,如果你无法控制所使用的标记,这是可能的。另一种改善非语义 JavaScript 驱动小部件可访问性的方法是使用 WAI-ARIA 为屏幕阅读器用户提供额外的语义。下一篇文章也将详细介绍这一点。

复杂功能,如 3D 游戏,并不容易做到无障碍——使用 WebGL 创建的复杂 3D 游戏将在 <canvas> 元素上渲染,该元素目前无法为严重视力障碍用户提供文本替代或其他信息。可以说,这样的游戏并不真正以这部分人群作为其主要目标受众,期望你使其对盲人 100% 无障碍是不合理的。然而,你可以实现键盘控制,使其可供非鼠标用户使用,并使配色方案对比度足够强,以便有色觉缺陷的人可以使用。

JavaScript 过多的问题

问题往往出现在人们过于依赖 JavaScript 的时候。有时你会看到一个网站,所有事情都用 JavaScript 完成——HTML 由 JavaScript 生成,CSS 由 JavaScript 生成,等等。这会带来各种无障碍和其他问题,因此不建议这样做。

除了为正确的工作使用正确的元素之外,你还应该确保为正确的工作使用正确的技术!仔细思考你是否需要那个闪亮的 JavaScript 驱动的 3D 信息框,或者纯文本是否也能做到。仔细思考你是否需要一个复杂的非标准表单小部件,或者一个文本输入是否也能做到。如果可能的话,不要使用 JavaScript 生成你所有的 HTML 内容。

保持非侵入性

创建内容时,你应该记住非侵入式 JavaScript。非侵入式 JavaScript 的理念是,应尽可能将其用于增强功能,而不是完全构建功能——基本功能 ideally 应在没有 JavaScript 的情况下工作,尽管有时这并不是一个选项。但同样,很大一部分是尽可能使用内置浏览器功能。

非侵入式 JavaScript 的良好示例用途包括

  • 提供客户端表单验证,在用户无需等待服务器检查数据的情况下,快速提醒用户其表单输入存在问题。如果不可用,表单仍将正常工作,但验证可能会较慢。
  • 为 HTML <video> 提供可供仅键盘用户访问的自定义控件,以及在 JavaScript 不可用时可用于访问视频的直接链接(默认的 <video> 浏览器控件在大多数浏览器中都无法通过键盘访问)。

举个例子,我们编写了一个快速简陋的客户端表单验证示例——请参阅form-validation.html(也请在线查看演示)。在这里你会看到一个简单的表单;当你尝试提交一个或两个字段为空的表单时,提交会失败,并出现一个错误消息框告诉你哪里出了问题。

这种表单验证是非侵入性的——在没有 JavaScript 的情况下,你仍然可以非常流畅地使用表单,并且任何合理的表单实现都会同时激活服务器端验证,因为恶意用户很容易绕过客户端验证(例如,通过在浏览器中关闭 JavaScript)。客户端验证对于报告错误仍然非常有用——用户可以立即了解他们所犯的错误,而不必等待往返服务器和页面重新加载。这是一个明确的可用性优势。

注意:在此简单演示中未实现服务器端验证。

我们也使这个表单验证非常无障碍。我们使用了<label> 元素,以确保表单标签与它们的输入明确关联,这样屏幕阅读器可以同时读出它们

html
<label for="name">Enter your name:</label>
<input type="text" name="name" id="name" />

我们只在表单提交时进行验证——这样做是为了我们不会过于频繁地更新 UI,从而可能混淆屏幕阅读器(以及可能其他)用户

js
form.onsubmit = validate;

function validate(e) {
  errorList.textContent = "";
  for (const testItem of formItems) {
    if (testItem.input.value === "") {
      errorField.style.left = "360px";
      createLink(testItem);
    }
  }

  if (errorList.hasChildNodes()) {
    e.preventDefault();
  }
}

注意:在此示例中,我们使用绝对定位而不是其他方法(例如可见性或显示)来隐藏和显示错误消息框,因为它不会干扰屏幕阅读器从中读取内容。

真实的表单验证会比这复杂得多——你会想要检查输入的姓名是否真的像姓名,输入的年龄是否真的是数字并且是真实的(例如,非负且小于 4 位)。这里我们只是实现了一个简单的检查,以确保每个输入字段都已填写值 (if (testItem.input.value === ''))。

验证执行完毕后,如果测试通过,则提交表单。如果存在错误 (if (errorList.hasChildNodes())),则我们停止表单提交(使用preventDefault()),并显示所有已创建的错误消息(见下文)。这种机制意味着错误只会存在错误时才会显示,这对于可用性更好。

对于表单提交时没有填写值的每个输入,我们都会创建一个带有链接的列表项,并将其插入到 errorList 中。

js
function createLink(testItem) {
  const listItem = document.createElement("li");
  const anchor = document.createElement("a");

  const name = testItem.input.name;
  anchor.textContent = `${name} field is empty: fill in your ${name}.`;
  anchor.href = `#${name}`;
  listItem.appendChild(anchor);
  errorList.appendChild(listItem);
}

每个链接都有双重作用——它告诉你错误是什么,此外你可以点击/激活它,直接跳转到相关的输入元素并更正你的输入。

此外,errorField 放置在源顺序的顶部(尽管它在 UI 中使用 CSS 定位不同),这意味着用户可以准确找出他们的表单提交出了什么问题,并通过返回页面开头找到相关的输入元素。

最后一点,我们在演示中使用了 WAI-ARIA 属性来帮助解决由于内容区域不断更新而无需重新加载页面所导致的可访问性问题(屏幕阅读器默认不会捕捉到或提醒用户)。

html
<div class="errors" role="alert" aria-relevant="all">
  <ul></ul>
</div>

我们将在下一篇文章中详细解释这些属性,该文章将更详细地介绍WAI-ARIA

注意:你们中的一些人可能会想到 HTML 表单具有内置的验证机制,例如 requiredmin/minlengthmax/maxlength 属性(有关更多信息,请参阅 <input> 元素参考)。我们最终在演示中没有使用这些,因为它们的跨浏览器支持不稳定(例如,仅 IE10 及更高版本)。

注意:WebAIM 的可用且无障碍的表单验证和错误恢复提供了有关无障碍表单验证的一些进一步有用信息。

其他 JavaScript 无障碍性问题

在实施 JavaScript 并考虑无障碍性时,还有其他需要注意的事项。我们会随着发现而添加更多。

鼠标特定事件

如你所知,大多数用户交互都是在客户端 JavaScript 中使用事件处理程序实现的,这使我们能够响应某些事件的发生来运行函数。某些事件可能存在无障碍性问题。你将遇到的主要示例是鼠标特定事件,如 mouseovermouseoutdblclick 等。响应这些事件运行的功能将无法通过其他机制(如键盘控制)进行访问。

为了缓解此类问题,你应该将这些事件与可以通过其他方式激活的类似事件(所谓的设备无关事件处理程序)结合起来——focusblur 将为键盘用户提供可访问性。

让我们看一个突出显示何时这可能很有用的示例。也许我们想提供一个缩略图,当鼠标悬停或聚焦时显示图像的放大版本(就像你在电子商务产品目录中看到的那样)。

我们制作了一个非常简单的示例,你可以在 mouse-and-keyboard-events.html 找到(另请参阅源代码)。代码包含两个显示和隐藏放大图像的函数;这些函数由以下行作为事件处理程序运行

js
imgThumb.onmouseover = showImg;
imgThumb.onmouseout = hideImg;

imgThumb.onfocus = showImg;
imgThumb.onblur = hideImg;

前两行分别在鼠标指针悬停在缩略图上和停止悬停在缩略图上时运行这些函数。但这不允许我们通过键盘访问缩放视图——为了实现这一点,我们包含了最后两行,它们在图像获得焦点和失焦(焦点停止时)时运行这些函数。这可以通过在图像上使用 Tab 键来完成,因为我们在图像上包含了 tabindex="0"

click 事件很有趣——它听起来是依赖鼠标的,但大多数浏览器会在链接或表单元素获得焦点后按下 Enter/Return 键时,或者在触摸屏设备上点击此类元素时激活 onclick 事件处理程序。然而,当你允许非默认可聚焦事件通过 tabindex 获得焦点时,这默认不起作用——在这种情况下,你需要专门检测何时按下该精确键(请参阅重新构建键盘可访问性)。

总结

我们希望本文能为你提供足够详细的信息和理解,了解网页上 CSS 和 JavaScript 使用所涉及的无障碍性问题。

在下一篇文章中,我们将为您提供一些测试,您可以使用它们来检查您对所有这些信息的理解和掌握程度。