如何将焦点保持在模态对话框中?

sma*_*use 6 accessibility modal-dialog wai-aria semantic-ui wcag2.0

我正在用Angular和开发一个应用程序Semantic-UI.应用程序应该是可访问的,这意味着它应该符合WCAG 2.0.为了达到这个目的,模态应该在对话框中保持焦点,并防止用户走出去或在位于模态下的页面元素之间移动"标签".

我找到了一些工作示例,如下所示:

这是我尝试用Semantic-UI创建一个可访问的模态:https://plnkr.co/edit/HjhkZg

如您所见,我使用了以下属性:

role="dialog"

aria-labelledby="modal-title"

aria-modal="true"

但他们没有解决我的问题.你有没有办法让我的模态保持专注,只有当用户点击取消/确认按钮时才会失去它?

Ste*_*ert 8

目前还没有简单的方法来实现这一目标.将惰性属性提出来尝试做任何元素与属性,这一切来解决这个问题的孩子无法访问.但是,采用速度很慢,直到最近它才落在Chrome Canary后面的旗帜上.

另一个提出的解决方案是创建一个本机API,它将跟踪模态堆栈,实质上使当前不是堆栈顶部的所有内容都是惰性的.我不确定提案的状态,但看起来不会很快实施.

那么我们离开了哪里呢?

不幸的是,没有一个好的解 一种流行的解决方案是创建所有已知可聚焦元素的查询选择器,然后通过向模态中的最后和第一个元素添加keydown事件来将焦点捕获到模态.但是,随着Web组件和shadow DOM的兴起,此解决方案无法再找到所有可聚焦元素.

如果你总是控制对话框中的所有元素(并且你没有创建一个通用的对话框库),那么最简单的方法就是在第一个和最后一个可聚焦元素上为keydown添加一个事件监听器,检查是否为tab或使用了shift选项卡,然后将第一个或最后一个元素聚焦到陷阱焦点.

如果你正在创建一个通用的对话框库,我发现的唯一合理的工作就是使用惰性polyfill或者使模态外的所有东西都有tabindex=-1.

var nonModalNodes;

function openDialog() {    
  var modalNodes = Array.from( document.querySelectorAll('dialog *') );

  // by only finding elements that do not have tabindex="-1" we ensure we don't
  // corrupt the previous state of the element if a modal was already open
  nonModalNodes = document.querySelectorAll('body *:not(dialog):not([tabindex="-1"])');

  for (var i = 0; i < nonModalNodes.length; i++) {
    var node = nonModalNodes[i];

    if (!modalNodes.includes(node)) {

      // save the previous tabindex state so we can restore it on close
      node._prevTabindex = node.getAttribute('tabindex');
      node.setAttribute('tabindex', -1);

      // tabindex=-1 does not prevent the mouse from focusing the node (which
      // would show a focus outline around the element). prevent this by disabling
      // outline styles while the modal is open
      // @see https://www.sitepoint.com/when-do-elements-take-the-focus/
      node.style.outline = 'none';
    }
  }
}

function closeDialog() {

  // close the modal and restore tabindex
  if (this.type === 'modal') {
    document.body.style.overflow = null;

    // restore or remove tabindex from nodes
    for (var i = 0; i < nonModalNodes.length; i++) {
      var node = nonModalNodes[i];
      if (node._prevTabindex) {
        node.setAttribute('tabindex', node._prevTabindex);
        node._prevTabindex = null;
      }
      else {
        node.removeAttribute('tabindex');
      }
      node.style.outline = null;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Ada*_*dam 6

不同的“工作示例”在屏幕阅读器中无法正常工作。

它们不会将屏幕阅读器的视觉焦点困在模态中。

为此,您必须:

  1. aria-hidden在任何其他节点上设置属性
  2. 禁用这些树中的键盘可聚焦元素(链接使用tabindex=-1,控件使用disabled,...)

  3. 在页面上添加一个透明层以禁用鼠标选择。

    • 或者您可以pointer-events: none在浏览器使用非 SVG 元素处理它时使用 css属性,而不是在 IE 中


Dan*_*non 6

这个焦点陷阱插件非常适合确保焦点保持在对话元素内。