简体   繁体   English

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

[英]How to prevent screen reader focus (not referring to keyboard focus) from leaving predefined area (e.g., modal)

I've been trying to figure out how to contain the screen reader focus within a certain area.我一直在试图弄清楚如何将屏幕阅读器的焦点包含在某个区域内。 When I say screen reader focus, I don't mean the default browser focus that one can move with tabbing/shift-tabbing.当我说屏幕阅读器焦点时,我并不是指可以通过 tabbing/shift-tabbing 移动的默认浏览器焦点。 I predominantly implement accessibility while using Voiceover on Mac, and when you turn that on, a new focus box appears on the page and reads out the information that it is 'highlighting'.我主要在 Mac 上使用 Voiceover 时实现辅助功能,当你打开它时,页面上会出现一个新的焦点框并读出它正在“突出显示”的信息。

At that point if you were to tab, both the browser and the screenreader focus move concurrently.此时,如果您要使用选项卡,浏览器和屏幕阅读器的焦点会同时移动。 Aside from tabbing to different focusable elements, you can also hold cmd + opt and keypress left and right to move the screen reader focus from element to element, regardless if one can tab to it.除了切换到不同的可聚焦元素之外,您还可以按住 cmd + opt 并左右按键将屏幕阅读器焦点从一个元素移动到另一个元素,无论是否可以对其进行切换。 That's the focus that I'm trying to contain.这就是我试图控制的焦点。

I've tried preventing cmd, opt, and arrow key key presses when the focus is on the last element that I want focusable, but the browser doesn't seem to recognize the screen reader focus.当焦点位于我想要聚焦的最后一个元素上时,我尝试阻止 cmd、opt 和箭头键按下,但浏览器似乎无法识别屏幕阅读器焦点。 And I believe that the keyboard disabling wouldn't work with the screen reader anyways, as it seems to work independently of the browser.而且我相信键盘禁用无论如何都不适用于屏幕阅读器,因为它似乎独立于浏览器工作。

I've also tried dynamically adding tabindex: -1 and aria-hidden: true to all other elements on the page when a modal appears.当模态出现时,我还尝试动态添加 tabindex: -1 和 aria-hidden: true 到页面上的所有其他元素。 This works when you turn on Voiceover after the fact;当您在事后打开画外音时,此方法有效; the screen reader focus does in fact get trapped.屏幕阅读器的焦点实际上确实被困住了。 However if the screen reader is on first, which likely will be the case in most user instances, the screen reader doesn't respect the dynamic change.但是,如果屏幕阅读器首先打开(在大多数用户实例中很可能是这种情况),则屏幕阅读器不会考虑动态变化。 It's like the screen reader takes a 'snapshot' of the accessibility state as the page loads, and it doesn't respect new changes to the DOM.就像屏幕阅读器在页面加载时拍摄可访问性 state 的“快照”,并且它不尊重 DOM 的新更改。

Anyone have any ideas?有人有想法么?

You can't prevent key shortcuts of the screen reader from being used.您无法阻止使用屏幕阅读器的快捷键。 They have priority over everything else.他们优先于其他一切。 They aren't even caught by a keydown/up/press handler within your script.它们甚至不会被脚本中的 keydown/up/press 处理程序捕获。 Fortunately for us as screen reader users, this isn't an acceptable way to go.对于我们作为屏幕阅读器用户来说幸运的是,这不是 go 可接受的方式。

As you also have observed, the browse cursor is effectively completely independant from the system focus.正如您还观察到的,浏览 cursor 实际上完全独立于系统焦点。 The accessibility tree determines what is reachable when using the screen reader's browse cursor.可访问性树确定使用屏幕阅读器浏览 cursor 时可访问的内容。

To temporarily restrict the elements seen by the browse cursor, you must use the aria-modal attribute.要暂时限制浏览 cursor 看到的元素,必须使用 aria-modal 属性。 Put it on the root element that should be reachable.将它放在应该可以访问的根元素上。 Everything inside will stay reachable.里面的一切都将保持可达。 Everything else outside will no longer be reachable as long as the attribute stays on the element.只要属性保留在元素上,外部的所有其他内容都将不再可访问。

Don't play with aria-hidden to produce the same effect.不要使用 aria-hidden 来产生相同的效果。 Some screen readers have issues with nested elements having an aria-hidden attribute.一些屏幕阅读器对具有 aria-hidden 属性的嵌套元素存在问题。 For example, if an outer element has aria-hidden=true and an inner element has aria-hidden=false, Jaws won't show the inner element.例如,如果外部元素具有 aria-hidden=true 而内部元素具有 aria-hidden=false,则 Jaws 不会显示内部元素。

Restricting the browse cursor with aria-modal, as well as hidding elements with aria-hidden by the way, doesn't automatically imply that they can't be focused with the regular system focus (Tab/Shift+Tab).使用 aria-modal 限制浏览 cursor,以及顺便用 aria-hidden 隐藏元素,并不意味着它们不能通过常规系统焦点 (Tab/Shift+Tab) 聚焦。 You will therefore usually double the aria-modal restriction with a focus trap to prevent the system focus from going to a place where it isn't expected.因此,您通常会使用焦点陷阱将 aria-modal 限制加倍,以防止系统焦点转到不期望的地方。 If you don't do it, you may create troubles for screen reader users (what should the screen reader do if the focus is currently on an element hidden from the accessibility tree?).如果不这样做,可能会给屏幕阅读器用户带来麻烦(如果当前焦点位于可访问性树中隐藏的元素上,屏幕阅读器应该怎么做?)。 This is a recurrent oversight.这是一个经常性的疏忽。

The safest to make a focus trap is to catch tab on the last allowed element and shift+tab on the first, and resp.制作焦点陷阱最安全的方法是在最后一个允许的元素上捕获制表符,并在第一个元素上捕获 shift+tab,然后分别。 bring the focus back to the first or last allowed element.将焦点带回第一个或最后一个允许的元素。 It's much easier than setting all focusable elements to tabindex=-1 and then back to tabindex=0, and as far as I have tested, it works almost everywhere.这比将所有可聚焦元素设置为 tabindex=-1 然后回到 tabindex=0 要容易得多,而且据我测试,它几乎可以在任何地方工作。

Here is a method I use to manage focus for modals which solves the issue you are having.这是我用来管理模态焦点的方法,可以解决您遇到的问题。

The item variable is the referring button that was pressed before opening the modal (so we can return focus there after closing the modal). item变量是在打开模态之前按下的引用按钮(因此我们可以在关闭模态后返回焦点)。

The className variable is the class name of the modal so you can target different modals. className变量是模态的 class 名称,因此您可以针对不同的模态。

kluio.helpers is just an array of functions I use across the site so can be omitted. kluio.helpers只是我在整个站点中使用的一组函数,因此可以省略。

kluio.globalVars is an array of global variables so could be substituted for returning the results from the function. kluio.globalVars是一个全局变量数组,因此可以替换为从 function 返回结果。

I have added comments to each part to explain what it does.我在每个部分都添加了注释来解释它的作用。

The setFocus function is called when the modal is opened passing in the element that was pressed to activate it and the modal's className (works for our use case better, you should use an ID instead). setFocus function 在打开模态时调用,传入按下以激活它的元素和模态的类名(更适合我们的用例,您应该使用 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)); //please note we use a custom replacement for jQuery, pretty sure .find() behaves identically but just check it yourself.
    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);
    }
}

We then intercept the keydown event with the following function to manage focus.然后我们用下面的 function 拦截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.
            }
        }
    }
};

Finally in your version of the closeAllModals function you need to return focus to the referring element.最后,在您的closeAllModals function 版本中,您需要将焦点返回到引用元素。

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

It works well for our use case and although it could do with a tidy and we have a few strange practices (global variables....we have good reasons I promise.) it will hopefully be of use to you.它适用于我们的用例,虽然它可以做一个整洁的工作并且我们有一些奇怪的做法(全局变量......我们有充分的理由我 promise。)它希望对你有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 打开后如何将屏幕阅读器焦点更改为 vuetify 模态? - How to change screen reader focus to vuetify modal once it opens? 在ember中将屏幕阅读器的焦点设置为模态警报 - Setting focus of a screen reader on a modal alert in ember 防止焦点离开表单字段 - prevent focus from leaving form fields 动态创建的输入。 不能使用$ refs来获取焦点? - Dynamically created input. Can't use $refs so how to get e.g. focus? 如何手动设置焦点(例如,右键单击-&gt;设置焦点)到网站上的元素? - Way to set focus manually (e.g. right click -> set focus) to an element on a website? 如何防止输入字段获得键盘焦点? - How to prevent input fields from gaining keyboard focus? 屏幕阅读器和HTML文档重点 - Screen reader and HTML document focus 当焦点从 aria-live 区域 div 获得输入字段时,如何防止屏幕阅读器停止阅读内容? - How can I prevent the screen reader from stopping to read the content when the focus is gained to the input field from an aria-live region div? 焦点/对焦点,用于响应式调整图像尺寸(例如,全宽页眉) - Focal point / focus point for responsive re-sizing images (e.g. full width header) 如何防止点击释放在背景上触发(例如在弹出覆盖中选择输入文本) - How to prevent a click release from firing on background (e.g. selecting input text in popup overlay)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM