“aria-hidden 元素不包含可聚焦元素"显示模态时的问题

我在我的应用程序中使用 React Modal 并且当它打开时运行 aXe 辅助工具 给出以下错误:

aria-hidden 元素不包含可聚焦元素

这是因为 React modal 向应用程序的根元素添加了一个 aria-hidden=true"(我的所有应用程序组件都在 div 下呈现,但不是 modal),但它不会更新选项卡索引或禁用每个可聚焦元素.

但是,React 模态会捕获键盘焦点,因此用户无法跳出模态并单击背景关闭模态.

所以我的问题是:

这真的是我需要解决的问题吗?或者这是一个误报,因为该工具不了解模态捕获焦点?

如果确实需要解决这个问题,我唯一的选择是手动更新选项卡索引还是禁用每个可聚焦元素?

谢谢!

模态框打开时的 HTML 看起来像这样:

解决方案

简答

aria-modal 添加到您的模态框将删除此警告.

长答案

我花了一段时间才明白为什么我们的模态框没有这个警告,而你的却有这个警告,因为我们使用了类似的标记.我们在模态框上使用 aria-modal 属性.

Axe 已更新为期望模态框上的 aria-modal 属性.aria-modal 目前有 平均支持,但它是一种很好的做法,因为它可以解决开发人员的错误(因为确实尊重它的屏幕阅读器/浏览器组合会自动为您捕获焦点!).

在模式之外隐藏项目

真正隐藏所有内容的唯一方法是将 tabindex=-1" 添加到每个交互项目中.

但实际上,如果用于向每个交互元素添加 tabindex=-1" 的 JS 函数遇到问题并且不会成功还原 tabindex 或将其删除.这意味着您让页面的某些部分完全无法访问!

很明显,你会在稳健"的 WCAG 上失败.POUR 的一部分.请不要这样做.

最好的折衷方案是在 <main><aside> 容器(任何顶级容器)上使用 aria-hidden).然后在您的模式上使用 aria-modal 因为这会在某些浏览器/屏幕阅读器组合中捕获焦点.aria 的组合将为浏览器支持提供最高的覆盖率.

最后,您应该使用 tab 键为人们管理焦点.这是我们的备份,以防上述方法失败以及不使用屏幕阅读器的人(即不能使用鼠标的灵巧或准确性问题的人).

如果您需要有关如何在模式中捕获选项卡焦点的信息,我将提供一个代码示例,但它非常简单.

管理标签键焦点不会阻止屏幕阅读器用户或行为不端的插件超出您的模式(如果其他方法失败)但相信我,如果他们在您实施后对您的网站有问题以上他们在其他网站上会有更大的问题.

惰性 - 给你的弓再添一根弦?

最后作为另一个备份,我们添加 inert 到我们模式之外的项目.支持不是很好,但每一点都有帮助!

您可以根据需要对其进行 polyfill,但我认为它尚未超出草案规范,因此我们只是按原样使用它.

它纯粹是作为另一个添加和(希望)将来证明我们的遗留应用程序,因为 inert 是一个非常需要且易于理解的属性.它在不改变视觉设计的情况下阻止屏幕阅读器访问项目(基本上是 aria-hidden,但作为标准属性,其优点是它可以有效地从可访问性树中删除所有子项.)

示例

尝试从以下示例中删除 aria-modal=true" 并运行 Axe,警告将返回.

<main aria-hidden="true" inert><a href="https://google.com">test</a></main><div class="modal" aria-hidden="false" aria-modal="true"><label for="iTest">输入测试</label><输入 id="iTest"/></div>

I'm using React Modal in my application and when it is open running the aXe accessibility tool gives the following error:

aria-hidden elements do not contain focusable elements

This is because the React modal adds a aria-hidden="true" to the root element of the application (the div all my apps components are rendered under, but not the modal), but it does not update the tab index or disable every focusable element.

However the React modal traps the keyboard focus, so the user can't tab out of the modal and clicking the background closes the modal.

So my question is:

Is this actually an issue I need to fix? Or is this a false positive as the tool doesn't have knowledge of the modal trapping focus?

If this does need to be fixed, is my only option to manually update the tab index or disable every focusable element?

Thanks!

The HTML when the modal is open looks kinda like this:

<div data-react-modal-body-trap="" tabindex="0" style="position: absolute; opacity: 0;"></div>
<div id="root" aria-hidden="true">application content</div>
<div class="ReactModalPortal">
    <div class="ReactModal__Overlay ReactModal__Overlay--after-open modal-overlay-6fODnA">
        <div tabindex="-1" role="dialog">modal content</div>
    </div>
</div>

解决方案

Short Answer

Adding aria-modal to your modal will remove this warning.

Long Answer

It took me a while to realise why our modals do not have this warning but yours would as we employ similar markup. We use the aria-modal property on our modals.

Axe has been updated to expect the aria-modal property on a modal. aria-modal has average support at the moment but it is a good practice as it counters developer mistakes (as screen reader / browser combos that do respect it will automatically trap focus for you!).

Hiding items outside a modal

The only way to truly hide everything is to add tabindex="-1" to every single interactive item.

However in reality that is far more likely to cause a catastrophic accessibility issue if your JS function you use to add tabindex="-1" to every interactive element encounters an issue and doesn't successfully revert the tabindex or remove it. This would mean you leave parts of the page completely inaccessible!

Obviously you would then fail WCAG on the "Robust" part of POUR. Please don't do this.

The best compromise is to use aria-hidden on the <main> and <aside> containers (any top level containers). Then use aria-modal on your modal as this will trap focus in some browser / screen reader combos. That combination of aria will provide the highest coverage for browser support.

Finally you should manage focus for people using the tab key. This is our backup in case the above methods fail and for people not using a screen reader (i.e. people with dexterity or accuracy issues who can't use a mouse.)

If you need information on how to trap the tab focus within a modal I will provide a code sample but it is pretty straight forward.

Managing tab key focus will not stop screen reader users or misbehaving plugins from getting outside your modal (if the other methods fail) but believe me, if they have a problem with your site after you implement the above they will have bigger problems on other sites.

inert - a further string to your bow?

Finally as another backup we add inert to the items outside of our modal. Support isn't great, but every little helps!

You can polyfill it if you want but I don't think it has moved outside of the draft spec yet so we just use it as is.

It is purely there as yet another add in and (hopefully) to future proof our legacy applications as inert is a much needed and easy to understand attribute. It blocks screen readers access to items without changing visual design (basically aria-hidden but as a standard attribute, with the advantage that it effectively removes all children from the accessibility tree.)

Example

Try removing the aria-modal="true" from the following example and running Axe, the warning will return.

<main aria-hidden="true" inert><a href="https://google.com">test</a></main>
<div class="modal" aria-hidden="false" aria-modal="true">
    <label for="iTest">input test</label>
    <input id="iTest"/>
</div>

相关文章