CSS 和 JavaScript 可访问性最佳实践
CSS 和 JavaScript 在正确使用的情况下,也具有提供无障碍网络体验的潜力,或者在误用时会严重损害无障碍性。本文概述了一些 CSS 和 JavaScript 最佳实践,应考虑这些最佳实践以确保即使是复杂的内容也尽可能地易于访问。
先决条件 | 对 HTML、CSS 和 JavaScript 的基本了解,以及对 什么是无障碍性 的理解。 |
---|---|
目标 | 熟悉在网页文档中适当使用 CSS 和 JavaScript 以最大程度地提高无障碍性,而不是降低无障碍性。 |
CSS 和 JavaScript 可访问吗?
CSS 和 JavaScript 在无障碍性方面没有 HTML 那样直接的重要性,但它们仍然能够帮助或损害无障碍性,具体取决于它们的使用方式。换句话说,重要的是您要考虑一些最佳实践建议,以确保您对 CSS 和 JavaScript 的使用不会破坏文档的无障碍性。
CSS
让我们从 CSS 开始。
正确的语义和用户预期
可以使用 CSS 使任何 HTML 元素看起来像 任何东西,但这并不意味着您应该这样做。正如我们在 HTML:无障碍性的良好基础 文章中经常提到的那样,您应该尽可能使用适合该工作的语义元素。如果您没有这样做,它会导致每个人,尤其是残疾用户,感到困惑和可用性问题。使用正确的语义与用户预期有很大关系——元素的外观和行为方式取决于它们的功能,用户期望这些常见约定。
例如,如果开发人员没有适当地使用标题元素来标记内容,屏幕阅读器用户就无法通过标题元素导航页面。同样,如果您将标题的样式设置为看起来不像标题,那么标题就会失去其视觉目的。
底线是,您可以更新页面功能的样式以适合您的设计,但不要更改太多,以至于它不再看起来或表现得像预期那样。以下部分总结了要考虑的主要 HTML 功能。
“标准”文本内容结构
标题、段落、列表——页面核心文本内容
<h1>Heading</h1>
<p>Paragraph</p>
<ul>
<li>My list</li>
<li>has two items.</li>
</ul>
一些典型的 CSS 可能看起来像这样
h1 {
font-size: 5rem;
}
p,
li {
line-height: 1.5;
font-size: 1.6rem;
}
您应该
- 选择合理的字体大小、行高、字距等,使您的文本逻辑、易读且舒适。
- 确保您的标题与正文文本区分开来,通常像默认样式那样大而粗体。您的列表应该看起来像列表。
- 您的文本颜色应与您的背景颜色形成良好对比。
强调文本
内联标记,赋予其包装的文本特定强调
<p>The water is <em>very hot</em>.</p>
<p>
Water droplets collecting on surfaces is called <strong>condensation</strong>.
</p>
您可能希望在强调文本中添加一些简单的颜色
strong,
em {
color: #a60000;
}
但是,您很少需要以任何重要方式为强调元素设置样式。粗体和斜体文本的标准约定非常容易识别,更改样式会导致混乱。有关强调的更多信息,请参阅 强调和重要性。
缩写
允许将缩写、首字母缩略词或缩写与其扩展关联的元素
<p>
Web content is marked up using Hypertext Markup Language, or
<abbr>HTML</abbr>.
</p>
同样,您可能希望以某种简单的方式对其进行样式设置
abbr {
color: #a60000;
}
缩写的公认样式约定是带点下划线,不建议大幅偏离它。有关缩写的更多信息,请参阅 缩写。
链接
超链接——您在网络上到达新地方的方式
<p>Visit the <a href="https://www.mozilla.org">Mozilla homepage</a>.</p>
下面显示了一些非常简单的链接样式
a {
color: #ff0000;
}
a:hover,
a:visited,
a:focus {
color: #a60000;
text-decoration: none;
}
a:active {
color: #000000;
background-color: #a60000;
}
标准链接约定在标准状态下是带下划线和不同颜色(默认:蓝色),链接被访问后是另一种颜色变化(默认:紫色),激活链接时又是另一种颜色(默认:红色)。此外,当鼠标悬停在链接上时,鼠标指针会变为指针图标,并且链接在获得焦点(例如通过制表符)或激活时会收到突出显示。下图显示了 Firefox(虚线轮廓)和 Chrome(蓝色轮廓)中的突出显示
您可以对链接样式进行创意设计,只要您在用户与链接交互时继续向用户提供反馈。在状态改变时肯定应该发生一些事情,并且您不应该去掉指针光标或轮廓——它们都是使用键盘控制的人非常重要的辅助功能。
表单元素
允许用户将数据输入网站的元素
<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 来选择它们)。
屏幕阅读器用户不关心所有这些——只要源顺序合理,并且他们可以访问所有内容,他们就会对内容感到满意。绝对定位(如在本示例中使用)通常被认为是出于视觉效果隐藏内容的最佳机制之一,因为它不会阻止屏幕阅读器访问内容。
另一方面,您不应该使用 visibility: hidden
或 display: none
,因为它们会将内容隐藏在屏幕阅读器之外。当然,除非有充分的理由要将此内容隐藏在屏幕阅读器之外。
注意: 仅供屏幕阅读器用户使用的不可见内容 提供了有关此主题的更多有用细节。
接受用户可以覆盖样式
用户可以使用自己的自定义样式覆盖您的样式,例如
- 请参阅 Sarah Maddox 的 如何在 Firefox 中使用自定义样式表 (CSS),这是一个有用的指南,介绍了如何在 Firefox 中手动执行此操作。
- 使用扩展程序可能更容易。例如,Stylus 扩展程序适用于 Firefox,Stylish 是 Chrome 的等效程序。
用户可能出于各种原因这样做。视障用户可能希望在他们访问的所有网站上将文本放大,或者患有严重色觉异常的用户可能希望将所有网站设置为高对比度颜色,这样他们更容易看到。无论出于何种需要,您都应该对此感到自在,并使您的设计足够灵活,以便这些更改能够在您的设计中正常工作。例如,您可能希望确保您的主要内容区域可以处理更大的文本(也许它会开始滚动以允许所有内容都可见),并且不会仅仅隐藏它,或者完全中断。
JavaScript
JavaScript 也可能破坏无障碍性,具体取决于它的使用方式。
现代 JavaScript 是一种功能强大的语言,我们现在可以用它做很多事情,从简单的内容和 UI 更新到功能齐全的 2D 和 3D 游戏。没有规定说所有内容都必须对所有人 100% 可访问——您只需要尽力而为,并使您的应用程序尽可能地易于访问。
简单的内容和功能可以说很容易使之变得无障碍——例如文本、图像、表格、表单和用于激活功能的按钮。正如我们在 HTML:无障碍性的良好基础 文章中所述,关键考虑因素是
- 良好的语义:为正确的工作使用正确的元素。例如,确保您使用标题和段落,以及
<button>
和<a>
元素 - 确保内容以文本形式提供,无论是直接作为文本内容,还是表单元素的良好文本标签,或者 文本替代,例如图像的 alt 文本。
我们还研究了如何在缺少功能的地方使用 JavaScript 来构建功能的示例——请参阅 重建键盘无障碍性。这不是理想的——实际上您应该为正确的工作使用正确的元素——但这表明在某些情况下,如果您无法控制所使用的标记,这仍然是可能的。另一种方法是使用 WAI-ARIA 为非语义 JavaScript 驱动的窗口小部件提供额外的语义,从而提高屏幕阅读器用户的无障碍性。下一篇文章也将详细介绍这一点。
像 3D 游戏这样的复杂功能并不容易实现无障碍性——使用 WebGL 创建的复杂 3D 游戏将在 <canvas>
元素上渲染,该元素目前还没有提供文本替代或其他信息以供严重视力障碍用户使用的功能。可以说,这类游戏并没有将这类人群作为其主要目标受众,要求你使其对盲人 100% 无障碍是不合理的。但是,你可以实现 键盘控制,使其可供非鼠标用户使用,并使颜色方案对比度足够高,以便色觉缺陷者可以使用。
过多的 JavaScript 问题
问题通常出现在人们过度依赖 JavaScript 的时候。有时你会看到一个网站,其中所有内容都是用 JavaScript 实现的——HTML 由 JavaScript 生成,CSS 由 JavaScript 生成,等等。这会带来各种无障碍性和其他问题,因此不建议这样做。
除了使用正确的元素来完成正确的工作之外,你还要确保你正在使用正确的技术来完成正确的工作!仔细考虑一下你是否需要那个闪闪发光的 JavaScript 驱动的 3D 信息框,或者简单的纯文本是否可以。仔细考虑一下你是否需要一个复杂的非标准表单小部件,或者文本输入是否可以。如果可能的话,不要使用 JavaScript 生成你所有的 HTML 内容。
保持非侵入性
在创建内容时,你应该牢记非侵入式 JavaScript 的理念。非侵入式 JavaScript 的理念是,它应该尽可能地用于增强功能,而不是完全构建功能——基本功能理想情况下应该在没有 JavaScript 的情况下工作,尽管我们认识到这并不总是一个选项。但是,再次强调,很大程度上是尽可能地使用内置的浏览器功能。
非侵入式 JavaScript 的一些很好的示例包括
- 提供客户端表单验证,在用户提交表单时快速提醒他们表单输入的问题,而无需等待服务器检查数据。如果它不可用,表单仍然可以工作,但验证可能会比较慢。
- 为 HTML
<video>
提供自定义控件,使其可供仅使用键盘的用户访问,以及一个指向视频的直接链接,以便在 JavaScript 不可用时访问视频(在大多数浏览器中,默认的<video>
浏览器控件无法通过键盘访问)。
例如,我们编写了一个快速简陋的客户端表单验证示例——请参阅 form-validation.html(还可以 查看演示)。在这里,你会看到一个简单的表单;当尝试提交表单时,如果一个或两个字段为空,提交将失败,并会出现一个错误消息框,告诉你哪里出了问题。
这种类型的表单验证是非侵入式的——即使没有 JavaScript,你仍然可以使用表单,任何合理的表单实现都将拥有服务器端验证,因为恶意用户很容易绕过客户端验证(例如,在浏览器中关闭 JavaScript)。客户端验证仍然非常有用,因为它可以报告错误——用户可以立即知道他们犯了什么错误,而不必等待往返服务器和页面重新加载。这是一个明显的可用性优势。
注意:服务器端验证在此简单演示中尚未实现。
我们还使这个表单验证变得非常无障碍。我们使用了 <label>
元素,确保表单标签明确地与它们的输入元素相关联,以便屏幕阅读器可以将它们与输入元素一起读出。
<label for="name">Enter your name:</label>
<input type="text" name="name" id="name" />
我们只在提交表单时进行验证——这样做的目的是为了避免过快地更新 UI,以免造成屏幕阅读器(以及其他用户)的混淆。
form.onsubmit = validate;
function validate(e) {
errorList.textContent = "";
for (let i = 0; i < formItems.length; i++) {
const testItem = formItems[i];
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
中。
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 属性来帮助解决由内容区域不断更新而没有页面重新加载(屏幕阅读器默认情况下不会拾取或提醒用户)造成的无障碍性问题。
<div class="errors" role="alert" aria-relevant="all">
<ul></ul>
</div>
我们将在下一篇文章中解释这些属性,该文章将更详细地介绍 WAI-ARIA。
注意:你们中有些人可能会想到,HTML 表单有内置的验证机制,例如 required
、min
/minlength
和 max
/maxlength
属性(有关更多信息,请参阅 <input>
元素参考)。我们在演示中没有使用这些属性,因为它们的跨浏览器支持存在问题(例如,IE10 及更高版本才支持)。
注意:WebAIM 的 可用且无障碍的表单验证和错误恢复 提供了一些关于无障碍表单验证的有用信息。
其他 JavaScript 无障碍性问题
在实现 JavaScript 并考虑无障碍性时,还有其他一些需要注意的事项。我们会在发现这些问题时添加更多内容。
特定于鼠标的事件
你可能知道,大多数用户交互都是使用客户端 JavaScript 通过事件处理程序实现的,事件处理程序允许我们根据发生的特定事件来运行函数。某些事件可能存在无障碍性问题。你会遇到一个主要的示例,即特定于鼠标的事件,如 mouseover、mouseout、dblclick 等。响应这些事件运行的功能无法通过其他机制(如键盘控制)访问。
为了缓解这些问题,你应该用可以通过其他方式激活的类似事件(即所谓的设备无关事件处理程序)来补充这些事件——focus 和 blur 将为键盘用户提供无障碍性。
让我们看一个突出显示何时可能有用处的示例。也许我们想要提供一个缩略图,当鼠标悬停在上面或获得焦点时,显示该图像的较大版本(就像你在电子商务产品目录中看到的那样)。
我们制作了一个非常简单的示例,你可以在 mouse-and-keyboard-events.html 中找到(还可以查看 源代码)。代码包含两个函数,用于显示和隐藏放大的图像;这两个函数由以下行运行,将它们设置为事件处理程序
imgThumb.onmouseover = showImg;
imgThumb.onmouseout = hideImg;
imgThumb.onfocus = showImg;
imgThumb.onblur = hideImg;
前两行分别在鼠标指针悬停在缩略图上和停止悬停在缩略图上时运行函数。但这不会让我们通过键盘访问放大视图——为了实现这一点,我们添加了最后两行,这两行分别在图像获得焦点和失去焦点(焦点停止)时运行函数。这可以通过将 Tab 键移到图像上来完成,因为我们已在图像上添加了 tabindex="0"
。
click 事件很有意思——它听起来像是依赖于鼠标的,但大多数浏览器会在按下链接或表单元素的 Enter/Return 键(已获得焦点)或在触摸屏设备上点击此类元素后,激活 onclick 事件处理程序。但是,默认情况下,如果你允许一个非默认可聚焦事件获得焦点,使用 tabindex,则它不会起作用——在这种情况下,你需要专门检测该键何时被按下(请参阅 重新构建键盘无障碍性)。
测试您的技能!
你已经阅读完这篇文章,但你还记得最重要的信息吗?在继续之前,你可以找到一些进一步的测试,以验证你是否保留了这些信息——请参阅 测试你的技能:CSS 和 JavaScript 无障碍性。