当 CSS 不够用时:可访问组件的 JavaScript 要求
已发表: 2022-03-10作为 ModernCSS.dev 的作者,我是 CSS 解决方案的大力支持者。 而且,我喜欢看到人们使用 CSS 进行真正开箱即用的设计和交互性的巧妙方式! 然而,我注意到使用“checkbox hack”之类的方法来推广“纯 CSS”组件的趋势。 不幸的是,像这样的黑客攻击使大量用户无法使用您的界面。
本文介绍了几个常见的组件,以及为什么 CSS 不足以通过详细说明 JavaScript 要求来涵盖可访问性。 这些要求基于 Web 内容可访问性指南 (WCAG) 和可访问性专家的额外研究。 我不会规定 JavaScript 解决方案或演示 CSS,而是检查创建每个组件时需要考虑的内容。 JavaScript 框架当然可以使用,但不是为了添加所讨论的事件和特性所必需的。
列出的要求基本上不是可选的——它们是帮助确保组件的可访问性所必需的。
如果您使用的是框架或组件库,您可以使用本文来帮助评估所提供的组件是否满足可访问性要求。 重要的是要知道,上面提到的许多项目不会被 aXe 等自动化可访问性测试工具完全覆盖,因此需要一些手动测试。 或者,您可以使用赛普拉斯之类的测试框架来为所需功能创建测试。
请记住,本文的重点是让您了解每个界面组件的 JavaScript 注意事项。 对于创建完全可访问的组件(例如必要的 aria 甚至标记)的所有实现细节,这并不是一个全面的资源。 每种类型都包含资源,以帮助您更多地了解每个组件的更广泛考虑因素。
确定仅 CSS 是否是合适的解决方案
在继续使用纯 CSS 解决方案之前,有几个问题要问。 我们将在更多上下文中介绍此处介绍的一些术语及其相关组件。
- 这是为了你自己的享受吗?
然后绝对全力以赴地使用 CSS,突破界限,学习这门语言可以做什么! - 该功能是否包括显示和隐藏内容?
然后,您需要 JS 至少切换 aria 并启用Esc
关闭。 对于也会改变状态的某些类型的组件,您可能还需要通过触发 ARIA 活动区域内的更新来传达更改。 - 自然对焦顺序是不是最理想?
如果自然顺序失去了触发器与其触发的元素之间的关系,或者键盘用户甚至无法通过自然 Tab 顺序访问内容,那么就需要 JS 来辅助焦点管理。 - 程式化控件是否提供有关功能的正确信息?
屏幕阅读器等辅助技术的用户接收基于语义和 ARIA 的信息,帮助他们确定控件的作用。 而且,语音识别的用户需要能够识别组件的标签或类型,以计算出用于操作控件的短语。 例如,如果您的组件的样式类似于选项卡,但使用单选按钮像选项卡一样“工作”,则屏幕阅读器可能会听到“单选按钮”,而语音用户可能会尝试使用“选项卡”一词来操作它们。 在这些情况下,您将需要 JS 来启用使用适当的控件和语义来实现所需的功能。 - 效果是否依赖悬停和/或焦点?
然后,您可能需要 JS 协助提供替代解决方案,以提供对内容的平等访问或持久访问,特别是对于触摸屏用户和使用 200%+ 桌面缩放或放大软件的用户。
快速提示:创建任何类型的自定义控件时的另一个参考是 W3“使用 ARIA”指南中的自定义控件可访问开发清单。 这提到了上面的几点,还有一些额外的设计和语义考虑。
工具提示
缩小工具提示的定义有点棘手,但在本节中,我们将讨论鼠标悬停在触发元素附近时出现的小文本标签。 它们覆盖其他内容,不需要交互,并在用户移除悬停或焦点时消失。

这里的纯 CSS 解决方案可能看起来完全没问题,可以通过以下方式完成:
<button class="tooltip-trigger">I have a tooltip</button> <span class="tooltip">Tooltip</span> .tooltip { display: none; } .tooltip-trigger:hover + .tooltip, .tooltip-trigger:focus + .tooltip { display: block; }
然而,这忽略了相当多的可访问性问题,并排除了许多用户访问工具提示内容。
一大群被排除在外的用户是那些使用触摸屏的用户,其中:hover
可能不会被触发,因为在触摸屏上, :hover
事件与:focus
事件同步触发。 这意味着连接到触发元素的任何相关操作(例如按钮或链接)都将与显示的工具提示一起触发。 这意味着用户可能会错过工具提示,或者没有时间阅读其内容。
在工具提示附加到没有事件的交互式元素的情况下,工具提示可能会显示但不会被关闭,直到另一个元素获得焦点,同时可能会阻止内容并阻止用户执行任务。
此外,需要使用缩放或放大软件进行导航的用户在使用工具提示时也会遇到相当大的障碍。 由于工具提示在悬停时显示,如果这些用户需要通过平移屏幕来更改他们的视野以阅读工具提示,它可能会导致它消失。 工具提示也会从用户那里移除控制权,因为通常没有什么可以告诉用户工具提示会提前出现。 内容的覆盖可能会阻止他们执行任务。 在某些情况下,例如绑定到表单域的工具提示、移动设备或其他屏幕键盘可能会掩盖工具提示内容。 而且,如果它们没有适当地连接到触发元素,一些辅助技术用户甚至可能不知道出现了工具提示。
工具提示行为的指导来自 WCAG Success Criterion 1.4.13 - Content on Hover or Focus。 该标准旨在帮助低视力用户和使用变焦和放大软件的用户。 工具提示(以及出现在悬停和焦点上的其他内容)的指导原则包括:
- 可解雇
无需移动悬停或焦点即可关闭工具提示 - 可悬停
显示的工具提示内容可以悬停而不会消失 - 执着的
附加内容不会因为超时而消失,而是等待用户移除悬停或焦点或以其他方式关闭它
要完全符合这些准则,需要一些 JavaScript 帮助,尤其是允许关闭内容。
- 辅助技术的用户会假设解雇行为与Esc键相关,这需要 JavaScript 侦听器。
- 根据下一节中描述的 Sarah Higley 的研究,在工具提示中添加可见的“关闭”按钮也需要 JavaScript 来处理其关闭事件。
- JavaScript 可能需要增强您的样式解决方案,以确保用户可以将鼠标悬停在工具提示内容上,而不会在用户移动鼠标时将其关闭。
工具提示的替代品
工具提示应该是最后的手段。 Sarah Higley - 一位对劝阻使用工具提示特别热衷的可访问性专家 - 提供了这个简单的测试:
“我为什么要将此文本添加到 UI 中? 还能去哪里?”
— Sarah Higley 来自演讲“工具提示:分为四个部分的调查”
根据 Sarah 在 Microsoft 担任职务时所参与的研究,另一种解决方案是专门的“toggletip”。 本质上,这意味着提供一个额外的元素来允许用户有意触发额外内容的显示和隐藏。 与工具提示不同,切换提示可以保留显示内容中元素的语义。 它们还让用户重新控制切换它们,并保留更多用户,特别是触摸屏用户的可发现性和可操作性。
如果您记得title
属性存在,只需知道它会遇到我们在纯 CSS 解决方案中提到的所有相同问题。 换句话说 - 不要在假设它是可接受的工具提示解决方案的情况下使用title
。
有关更多信息,请查看 Sarah 在 YouTube 上的演示文稿以及她关于工具提示的大量文章。 要了解有关 tooltips 与 toggletips 的更多信息以及有关为什么不使用title
的更多信息,请查看 Heydon Pickering 的 Inclusive Components: Tooltips and Toggletips 文章。
模态
模态框(也称为灯箱或对话框)是在触发操作后出现的页内窗口。 它们覆盖其他页面内容,可能包含结构化信息,包括附加操作,并且通常具有半透明背景以帮助将模式窗口与页面的其余部分区分开来。

我已经看到了一些纯 CSS 模式的变体(并且为我的投资组合的旧版本制作了一个感到内疚)。 他们可能会使用“checkbox hack”,利用:target
的行为,或者尝试使用:focus
来改造它(这可能真的是一个变相的过大工具提示)。
至于 HTML dialog
元素,请注意它不被认为是全面可访问的。 因此,虽然我绝对鼓励人们在自定义解决方案之前使用原生 HTML,但不幸的是,这打破了这个想法。 您可以了解有关 HTML dialog
为何不可访问的更多信息。
与工具提示不同,模式旨在允许结构化内容。 这意味着潜在的标题、一些段落内容和交互式元素,如链接、按钮甚至表单。 为了让大多数用户访问该内容,他们必须能够使用键盘事件,尤其是选项卡。 对于较长的模态内容,箭头键还应保留滚动功能。 和工具提示一样,它们应该可以用Esc键关闭——而且没有办法只用 CSS 来启用它。

模态框内的焦点管理需要 JavaScript。 模态框应该捕获焦点,这意味着一旦焦点在模态框内,用户不应该能够将其跳出到它后面的页面内容中。 但首先,焦点必须进入模态,这也需要 JavaScript 才能获得完全可访问的模态解决方案。
以下是必须使用 JavaScript 管理的与模式相关的事件序列:
- 按钮上的事件侦听器打开模式
- 焦点放在模态中; 哪个元素根据模态内容而变化(参见决策树)
- 焦点被困在模态中,直到它被解除
- 优选地,如果需要确认模式内容,除了专用关闭按钮或诸如“取消”之类的破坏性按钮动作之外,用户还能够使用Esc键关闭模式
- 如果允许Esc ,则单击模态背景也应关闭模态
- 解除后,如果未发生导航,则焦点将重新放在触发按钮元素上
模态焦点决策树
基于 WAI-ARIA 创作实践模态对话框示例,这里是一个简化的决策树,用于在打开模态后将焦点放在何处。 上下文将始终决定这里的选择,理想情况下,焦点比简单的“第一个可聚焦元素”更进一步管理。 事实上,有时需要选择不可聚焦的元素。
- 模态的主要主题是一种形式。
关注第一个表单域。 - 模态内容的长度很重要,并且会将模态动作推到视野之外。
关注标题(如果存在)或第一段。 - 模态的目的是具有多个可用操作的程序性(例如:操作确认)。
专注于基于上下文的“破坏性最小”操作(例如:“OK”)。 - 模态的目的是一个动作的程序。
专注于第一个可聚焦元素
快速提示:在需要聚焦不可聚焦元素(例如标题或段落)的情况下,添加tabindex="-1"
允许元素以编程方式通过 JS 聚焦但不将其添加到 DOM 选项卡顺序.
有关设置 ARIA 的其他要求以及有关如何选择要添加焦点的元素的其他详细信息,请参阅 WAI-ARIA 模态演示。 该演示还包括 JavaScript 以举例说明如何进行焦点管理。
对于现成的解决方案,Kitty Giraudel 创建了一个包含我们讨论的功能要求的 11y 对话框。 Adrian Roselli 还研究了模态对话框的焦点管理,并创建了一个演示并汇编了有关不同浏览器和屏幕阅读器组合如何传达焦点元素的信息。
标签
选项卡式界面涉及一系列触发器,一次显示一个相应的内容面板。 您可能会发现这些 CSS “hacks”涉及使用风格化的单选按钮或:target
,它们都允许一次只显示一个面板。

以下是需要 JavaScript 的选项卡功能:
- 将
aria-selected
属性切换为当前选项卡的 true 和未选择的选项卡的 false - 创建一个巡回标签索引以区分标签选择和焦点
- 通过响应箭头键事件(以及可选的
Home
和End
)在选项卡之间移动焦点
Optionally, you can make tab selection follow focus — meaning when a tab is focused its also then selected and shows its associated tab panel. WAI-ARIA 创作实践提供了本指南,用于选择是否应关注焦点。
无论您是否选择让选择跟随焦点,您还将使用 JavaScript 侦听箭头键事件以在选项卡元素之间移动焦点。 这是一种允许选项卡选项导航的替代模式,因为使用漫游选项卡索引(如下所述)会改变自然的键盘选项卡焦点顺序。
关于 Roving tabindex
漫游tabindex的概念是tabindex
值的值是通过程序控制来管理元素的焦点顺序的。 关于选项卡,这意味着通过设置tabindex="0"
,只有选定的选项卡是焦点顺序的一部分,而未选定的选项卡被设置为tabindex="-1"
,这会将它们从自然键盘焦点顺序中删除。
这样做的原因是为了选择选项卡时,下一个选项卡将在“相关”选项卡面板中登陆用户的焦点。 您可以选择通过为其分配tabindex="0"
来使作为选项卡面板的元素具有焦点,或者如果保证选项卡面板中的可焦点元素,则可能没有必要。 如果您的选项卡面板内容将更加多变或复杂,您可以考虑根据我们为模态审查的决策树来管理焦点。
示例选项卡模式
以下是创建选项卡的一些参考模式:
- 来自 Deque 大学的 Tabpanel 演示
- Scott O'Hara 的标签小部件测试(测试几种功能模式)
- Heydon Pickering 的Inclusive Components中的选项卡式界面,它演示了选项卡如何逐步增强目录
旋转木马
轮播也称为幻灯片或滑块,涉及一系列旋转内容面板(也称为“幻灯片”),其中包括控制机制。 您会在许多配置中找到这些内容,并且内容范围很广。 众所周知,它们被认为是一种糟糕的设计模式。

关于纯 CSS 轮播的棘手部分是它们可能不提供控件,或者它们可能使用意想不到的控件来操纵轮播运动。 例如,您可以再次使用“checkbox hack”来使轮播转换,但复选框会向辅助技术用户传递错误类型的交互信息。 此外,如果您将复选框标签设置为在视觉上显示为向前和向后箭头,您可能会给语音识别软件的用户一个错误的印象,即他们应该说些什么来控制轮播。
最近,对滚动捕捉的原生 CSS 支持已经落地。 起初,这似乎是完美的纯 CSS 解决方案。 但是,即使是自动可访问性检查也会将这些标记为键盘用户无法导航的,以防无法通过交互式元素导航它们。 此功能的默认行为还有其他可访问性和用户体验问题,其中一些我已包含在 SmolCSS 上的滚动快照演示中。
尽管轮播的外观多种多样,但仍有一些共同特征。 一种选择是使用标签标记创建轮播,因为它实际上是相同的底层界面,但视觉呈现有所改变。 与标签相比,轮播可能会为上一个和下一个提供额外的控制,如果轮播自动播放,也会暂停。
以下是 JavaScript 的注意事项,具体取决于您的轮播功能:
- 使用分页控件
选择编号项目后,以编程方式聚焦关联的轮播幻灯片。 这将涉及使用漫游 tabindex 设置幻灯片容器,以便您可以聚焦当前幻灯片,但防止访问屏幕外幻灯片。 - 使用自动播放
包括一个暂停控件,并且还可以在幻灯片悬停或其中的交互式元素获得焦点时启用暂停。 此外,您可以检查 JavaScript 中的prefers-reduced-motion
以在暂停状态下加载幻灯片以尊重用户偏好。 - 使用上一个/下一个控件
包括一个标记为aria-live="polite"
的视觉隐藏元素,并在激活这些控件后,使用当前位置的指示填充实时区域,例如“Slide 2 of 4”。
构建无障碍旋转木马的资源
- 完整的实现细节和注意事项以及来自 W3C Web Accessibility 轮播教程的完整代码示例
- Deque大学将tab界面增强为轮播的例子
- 自动旋转图像轮播的 WAI-ARIA 创作实践示例
- Smashing 的可访问组件综述中的轮播资源选择
下拉菜单
这是指一个组件,其中按钮切换打开链接列表,通常用于导航菜单。 停止在:hover
或:focus
上显示菜单的 CSS 实现只会错过一些重要的细节。

我承认,我什至认为通过使用更新的:focus-within
属性,我们可以安全地实现纯 CSS 解决方案。 您会看到我关于 CSS 下拉菜单的文章已被修改,以包含有关必要 JavaScript 的注释和资源(我保留了标题,以便寻求该解决方案的其他人也有望完成 JS 实现)。 具体来说,仅依赖 CSS 意味着违反了 WCAG 成功标准 1.4.13:我们通过工具提示了解到的悬停或焦点内容。
我们需要在 JavaScript 中添加一些此时听起来应该很熟悉的技术:
- 通过监听
click
事件在true
之间切换菜单按钮上的aria-expanded
false
- 使用Esc键关闭打开的菜单,并将焦点返回到菜单切换按钮
- 最好在焦点移到菜单外时关闭打开的菜单
- 可选:实现箭头键以及
Home
和End
键,用于在菜单切换按钮和下拉菜单中的链接之间进行键盘导航
快速提示:通过将菜单显示与.dropdown-toggle[aria-expanded=
"
true
"
] + .dropdown
的选择器相关联,而不是将菜单显示基于附加 JS- 的存在,确保下拉菜单的正确实现添加了类似active
的类。 这也消除了 JS 解决方案的一些复杂性!
这也称为“披露模式”,您可以在 WAI-ARIA 创作实践的示例披露导航菜单中找到更多详细信息。
有关创建可访问组件的其他资源
- Smashing 的可访问前端组件完整指南
- Carie Fisher 的文章 Good, Better, Best:解开可访问模式的复杂世界
- WAI-ARIA 创作实践 1.2 中提供的常见设计模式和小部件的演示和信息
- Deque 大学的代码库
- Scott O'Hara 的无障碍组件
- Heydon Pickering 的包容性组件