ARIA 友好的弹出窗口,可以从中跳出

ARIA friendly popover that can be tabbed out of

我想在包含一些输入字段的一些数据旁边创建一个弹出窗口。假设我们有以下文档结构

<input name="before-the-data" type="text />
<div id="the-data"><!-- presents some data --></div>
<input name="after-the-data" type="text />

当您从 before-the-data 向前切换时,弹出窗口应该打开并且焦点应该转到此弹出窗口中的第一个输入。这个 popover 被附加到正文有点像 material-ui 中的 Modal,所以它位于其余内容之上。同样,当您从 after-the-data.

向后切换时,弹出窗口应该打开

出于导航目的,弹出框的行为应如同在 #the-data 内部,但出于展示目的,实际位置应位于 <body> 的末尾。

为了达到这种效果,我在 #the-data 上设置了 tabindex="0" 并触发打开模式并将焦点转移到其中。到目前为止效果很好。

现在问题来了:如何最好地创建以下效果? 您应该能够导航回模态。我的想法是:当焦点从它转移或用户在模态框外单击时,我们关闭它并将焦点恢复到在它打开之前具有焦点的元素。这可以通过简单的 onblur 处理程序和背板上的 onclick 来完成。为了支持制表符,生成的模态看起来像这样:

<div id="backplane" onclick="closeAndRestoreFocus()"
                    onfocusout="checkCloseAndRestoreFocus()">
    <div id="beforecanary" onfocus="shiftFocusBefore()" tabindex="0"/>
    <!-- popover content -->
    <div id="aftercanary" onfocus="shiftFocusAfter()" tabindex="0"/>
</div>

您可以看到我添加了两个 div,您可以将它们切换到 beforecanaryaftercanary。当他们获得焦点时,他们将焦点分别转移到 before-the-dataafter-the-data,以模拟弹出窗口实际上就在 #the-data.

至此,您希望已经理解我要创建的内容。因此,问题是:这种方法在可访问性方面的总体效果如何?我如何确保遵循 WAI-ARIA 的最佳实践?

we close it and restore focus to the element that had focus before it opened up

这可能被认为是标签陷阱,2.1.2 No Keyboard Trap. Isn't the element that had focus before the popup the #the-data? So if I tab from before-the-data to #the-data, the popup will open. If I press esc to close the popup (you didn't mention that esc would close the popup but it should),焦点返回到 #the-data,这将自动再次打开弹出窗口,不是吗? (因为又是 onfocus() 运行。)

如果我只是 tab 完成整个过程,我认为它会起作用。只是关闭导致问题的弹出窗口。直接通过 Tab 键将焦点从 before-the-data 移动到 #the-data 到弹出窗口中的元素到 after-the-data 然后到页面的其余部分,对吧?

当从 after-the-data#the-data 向后跳格时,焦点是否移动到弹出窗口中的 last 元素?因为我要向后跳格,所以它需要在最后一项上,这样我才能继续通过弹出窗口向后跳格,然后到 before-the-data.

The popover should behave as if it were inside #the-data for navigation purposes but the actual position would be at the end of <body> for presentation purposes.

如果弹出窗口位于 DOM 最后,则不允许自然的 Tab 键顺序。你当然可以把它放在那里,但你必须管理选项卡顺序。如果弹出窗口真的是 #the-data 的一部分,那就简单多了。然后浏览器自然地处理 Tab 键顺序。

您还必须小心自动打开弹出窗口,但它可能违反了3.2.1 On Focus. See "Example of a Failure: A help dialog”。它有点 描述了你在做什么,但有点不同。在失败的例子中,焦点移动到输入字段,弹出窗口自动打开,焦点从输入移动到弹出窗口。你的情况有点不同,因为您首先将焦点从输入(或 before-the-data)上移开,然后显示弹出窗口,这 不会 违反 3.2.1。我只是想指出这一点,以防万一更改您的交互模型。

总之,您当前的行为有点像 skip link。跳过链接通常实现为 "hidden" 链接,仅当您 tab 到它们时才可见,并允许您跳转到页面上的某个位置。它们在焦点上变得可见的事实是您的弹出窗口的工作方式(因为它在获得焦点时也变得可见)。不同之处在于,如果您按 esc,跳过链接不会关闭。如果您在它们之外单击,它们 关闭。我认为这就是您要模仿的行为。如果您之前忽略了我关于 esc 应该关闭您的弹出窗口的评论,那么您会没事的。我只有那个评论,因为听起来你的弹出窗口就像一个模态对话框。