如何在打开时仅限制模式弹出窗口内的tab键?

时间:2018-05-04 15:30:24

标签: html5 angular modal-dialog accessibility onfocus

我打开了一个模态弹出窗口。我有无障碍要求。所以添加了ARIA相关标签。但是,当我单击tab键时,会继续将焦点转到实际页面后面的页面。

添加了角色="对话框"在html文件中

但是当模态打开时,我只希望焦点在模态弹出窗口中导航。

处理Angular4, HTML5项目。 如果我们在HTML文件中找到解决方案,那就更好了。 我的意思是没有添加任何javascript / jQuery相关的东西来阻止这个

7 个答案:

答案 0 :(得分:3)

您在询问焦点陷阱,在此演示中很好地展示了它:http://davidtheclark.github.io/focus-trap/demo/

添加role="dialog"不会自动为该元素提供陷阱焦点。事实上,浏览器提供了无本地焦点陷阱

您需要使用以下选项之一:

答案 1 :(得分:3)

小心任何依赖于javascript事件的方法,因为它无法正确处理屏幕阅读器

但是,如果没有类似已经在多个问题中指出的javascript,这是无法实现的 How to keep focus within modal dialog?

您有三个步骤:

1。通过在其上设置aria-hidden=true来禁用屏幕阅读器与任何其他节点的交互

例如:

<main aria-hidden="true"><!-- main content here--></main>
<dialog>Your dialog here</dialog>

2。禁用与它们的任何键盘交互

这必须在Javascript /或jQuery中完成。

这是jQuery中的单行指令,使用jquery-ui

$("main :focusable").addClass("disabled").attr("tabindex", -1);

反过来可以使用:

$(".disabled").removeClass("disabled").attr("tabindex", 0);

3。删除这些元素的任何指针事件以禁用鼠标交互

css样本:

main[aria-hidden='true'] { pointer-events: none;}

答案 2 :(得分:2)

仅在模式输入元素中循环的非jquery解决方案


// place this line in the dialog show function - to only add the listener when the dialog is shown
window.addEventListener('keydown', handleKey);

// uncomment and place this in the dialog close/hide function to remove the listener when dialog is closed/hidden
// window.removeEventListener('keydown', handleKey);

function handleKey(e) {
    if (e.keyCode === 9) {
        let focusable = document.querySelector('#modal').querySelectorAll('input,button,select,textarea');
        if (focusable.length) {
            let first = focusable[0];
            let last = focusable[focusable.length - 1];
            let shift = e.shiftKey;
            if (shift) {
                if (e.target === first) { // shift-tab pressed on first input in dialog
                    last.focus();
                    e.preventDefault();
                }
            } else {
                if (e.target === last) { // tab pressed on last input in dialog
                    first.focus();
                    e.preventDefault();
                }
            }
        }
    }
}

答案 3 :(得分:0)

这是我的解决方案。它会根据需要在模式对话框的第一个/最后一个元素上捕获Tab或Shift + Tab(在我的情况下为role="dialog")。被检查的合格元素是所有可见的输入控件,它们的HTML可能是input,select,textarea,button

$(document).on('keydown', function(e) {
    var target = e.target;
    var shiftPressed = e.shiftKey;
    // If TAB key pressed
    if (e.keyCode == 9) {
        // If inside a Modal dialog (determined by attribute role="dialog")
        if ($(target).parents('[role=dialog]').length) {                            
            // Find first or last input element in the dialog parent (depending on whether Shift was pressed). 
            // Input elements must be visible, and can be Input/Select/Button/Textarea.
            var borderElem = shiftPressed ?
                                $(target).closest('[role=dialog]').find('input:visible,select:visible,button:visible,textarea:visible').first() 
                             :
                                $(target).closest('[role=dialog]').find('input:visible,select:visible,button:visible,textarea:visible').last();
            if ($(borderElem).length) {
                if ($(target).is($(borderElem))) {
                    return false;
                } else {
                    return true;
                }
            }
        }
    }
    return true;
});

答案 4 :(得分:0)

现在,Angular CDK还提供了向模态弹出窗口https://material.angular.io/cdk/a11y/api#CdkTrapFocus添加焦点陷阱的指令

答案 5 :(得分:0)

父对话框元素应具有role="dialog"来指示这是一个对话框。 在您的情况下,您还缺少aria-modal="true",它应该告诉浏览器和屏幕阅读器焦点应该只停留在模式中。

使用aria-modal="true"代替了为应从屏幕阅读器隐藏且在模式打开时不会在模式之外接收键盘焦点的元素添加aria-hidden="true"的需求。

如果上述方法不起作用,您可能仍希望对模式外部的父元素使用aria-hidden="true",以防止键盘离开模式。

如果由于某些原因仍然无法使用,并且您需要手动控制键盘焦点,则可以检查哪些元素在模式之外获得键盘焦点,然后将其tabindex属性设置为tabindex="-1",这意味着它们仍然可以接收聚焦,而不是键盘。在这种方法中,您需要小心,因为当模式关闭时,您将希望通过从这些元素中删除tabindex="-1"或将其设置回tabindex="0"

来恢复功能。

来源:W3C wai aria practices - dialog modal with example

答案 6 :(得分:0)

尝试使用 tabindex='-1' 和其他 HTML 更改 的不同解决方案,但在我的情况下没有任何效果,所以这里有一些对我的情况有效的方法。

第 1 步:在对话框组件上添加 keydown 事件

  @HostListener('document:keydown', ['$event'])
  handleTabKeyWInModel(event: any) {
       this.sharedService.handleTabKeyWInModel(event, '#modal_id', this.elementRef.nativeElement, 'input,button,select,textarea,a,[tabindex]:not([tabindex="-1"])');
  }

这将过滤在模态对话框中预设的元素。

第 2 步:在共享服务中为处理焦点添加通用方法(或者您也可以将其添加到您的组件中) >

handleTabKeyWInModel(e, modelId: string, nativeElement, tagsList: string) {
        if (e.keyCode === 9) {
            const focusable = nativeElement.querySelector(modelId).querySelectorAll(tagsList);
            if (focusable.length) {
               const first = focusable[0];
               const last = focusable[focusable.length - 1];
               const shift = e.shiftKey;
               if (shift) {
                  if (e.target === first) { // shift-tab pressed on first input in dialog
                     last.focus();
                     e.preventDefault();
                  }
                } else {
                    if (e.target === last) { // tab pressed on last input in dialog
                        first.focus();
                        e.preventDefault();
                    }
                }
            }
        }
    }

现在此方法将采用模态对话框原生元素并开始对每个tab键进行评估。最后,我们将过滤第一个和最后一个事件,以便我们可以关注适当的元素(在最后一个元素选项卡点击后的第一个和第一个元素上的最后一个 shift+tab 事件)。

快乐编码.. :)