如何防止屏幕阅读器焦点(不涉及键盘焦点)离开预定义区域(例如,模态)

问题描述 投票:0回答:2

我一直试图弄清楚如何将屏幕阅读器焦点包含在特定区域内。当我说屏幕阅读器焦点时,我并不是说可以通过按Tab键/ Shift-Tab键移动的默认浏览器焦点。我主要在Mac上使用Voiceover时实现了可访问性,当您打开它时,页面上会出现一个新的焦点框,并读出“突出显示”的信息。

此时,如果要使用Tab键,浏览器和屏幕阅读器的焦点将同时移动。除了制表符以外,您还可以按住cmd + opt和左右键来将屏幕阅读器的焦点从一个元素移到另一个元素,无论是否可以将其切换到该元素。这就是我要包含的重点。

当焦点位于我要聚焦的最后一个元素上时,我尝试防止按cmd,opt和箭头键,但是浏览器似乎无法识别屏幕阅读器的焦点。而且我认为禁用键盘无论如何都不能与屏幕阅读器一起使用,因为它似乎独立于浏览器工作。

我还尝试过在出现模式时对页面上的所有其他元素动态添加tabindex:-1和aria-hidden:true。事后打开“画外音”时,此功能有效;屏幕阅读器的焦点实际上确实被困住了。但是,如果首先打开屏幕阅读器(在大多数用户实例中可能是这种情况),则屏幕阅读器将不考虑动态变化。就像屏幕阅读器在页面加载时获取可访问性状态的“快照”一样,它不考虑对DOM的新更改。

有人有什么想法吗?

javascript accessibility wai-aria
2个回答
1
投票

您无法阻止使用屏幕阅读器的快捷键。他们优先于其他一切。它们甚至不会被脚本中的keydown / up / press处理程序捕获。对于我们作为屏幕阅读器用户来说,幸运的是,这不是可接受的方法。

您也已经观察到,浏览光标实际上完全独立于系统焦点。可访问性树确定使用屏幕阅读器的浏览光标时可以访问的内容。

要临时限制浏览光标所看到的元素,必须使用aria-modal属性。将其放在应该可到达的根元素上。里面的所有东西都将保持可达。只要属性保留在元素上,外部其他所有内容都将无法访问。

请勿与隐藏的咏叹调玩耍以产生相同的效果。一些屏幕阅读器会遇到具有aria-hidden属性的嵌套元素的问题。例如,如果外部元素具有aria-hidden = true,而内部元素具有aria-hidden = false,则下颌将不会显示内部元素。

用aria-modal限制浏览光标,以及用aria-hidden来隐藏元素,并不自动暗示它们不能以常规系统焦点(Tab / Shift + Tab)进行聚焦。因此,您通常会使用焦点陷阱将aria-modal限制加倍,以防止系统焦点移到预期之外的地方。如果不这样做,可能会给屏幕阅读器用户带来麻烦(如果焦点当前位于可访问性树中隐藏的元素上,屏幕阅读器应该怎么办?)。这是经常性的监督。

进行焦点陷阱的最安全方法是在最后一个允许的元素上捕获选项卡,在第一个允许的元素上捕获Shift + Tab,然后分别。将焦点返回到允许的第一个或最后一个元素。比将所有可聚焦元素设置为tabindex = -1然后再返回tabindex = 0容易得多,据我测试,它几乎可以在任何地方使用。


0
投票

这是我用来管理模态焦点的方法。

item变量是在打开模态之前已按下的引用按钮(因此我们可以在关闭模态后返回焦点。)>

className变量是模态的类名,因此您可以定位不同的模态。

[kluio.helpers只是我在网站上使用的一系列功能,因此可以省略。

kluio.globalVars是全局变量的数组,因此可以用来代替从函数返回结果的方法。

我已在每个部分中添加注释以解释其功能。

setFocus函数在打开模态时会被调用,传入被按下以激活它的元素和模态的className(在我们的使用案例中更好,请改用ID)。

var kluio = {};
kluio.helpers = {};
kluio.globalVars = {};

kluio.helpers.setFocus = function (item, className) {

    className = className || "content"; //defaults to class 'content' in case of error (content being the <main> element.
    kluio.globalVars.beforeOpen = item; //we store the button that was pressed before the modal opened in a global variable so we can return focus to it on modal close.

    var focusableItems = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', '[tabindex="0"]']; //a list of items that should be focusable.
    var findItems = [];
    for (i = 0, len = focusableItems.length; i < len; i++) {
        findItems.push('.' + className + " " + focusableItems[i]); //add every focusable item to an array.
    }

    var findString = findItems.join(", ");
    kluio.globalVars.canFocus = Array.prototype.slice.call($('body').find(findString));
    if (kluio.globalVars.canFocus.length > 0) {
        setTimeout(function () { //set timeout not needed most of the time, we have a modal that is off-screen and slides in, setting focus too early results in the page jumping so we added a delay.
            kluio.globalVars.canFocus[0].focus(); //set the focus to the first focusable element within the modal
            kluio.globalVars.lastItem = kluio.globalVars.canFocus[kluio.globalVars.canFocus.length - 1]; //we also store the last focusable item within the modal so we can keep focus within the modal. 
        }, 600);
    }
}

然后我们使用以下函数来拦截keydown事件以管理焦点。

document.onkeydown = function (evt) {
    evt = evt || window.event;
    if (evt.keyCode == 27) {
        closeAllModals(); //a function that will close any open modal with the Escape key
    }
    if (kluio.globalVars.modalOpen && evt.keyCode == 9) { //global variable to check any modal is open and key is the tab key
        if (evt.shiftKey) { //also pressing shift key
            if (document.activeElement == kluio.globalVars.canFocus[0]) { //the current element is the same as the first focusable element
                evt.preventDefault();
                kluio.globalVars.lastItem.focus(); //we focus the last focusable element as we are reverse tabbing through the items.
            }
        } else {
            if (document.activeElement == kluio.globalVars.lastItem) { //when tabbing forward we look for the last tabbable element 
                evt.preventDefault();
                kluio.globalVars.canFocus[0].focus(); //move the focus to the first tabbable element.
            }
        }
    }
};

最后,在您的closeAllModals函数版本中,您需要将焦点返回到引用元素。

if (kluio.globalVars.beforeOpen) {
    kluio.globalVars.beforeOpen.focus();
}

[它对于我们的用例很好用,尽管它可以做得很整洁,并且我们有一些奇怪的做法(全局变量...。我保证有很好的理由!)它有望对您有用。

© www.soinside.com 2019 - 2024. All rights reserved.