简体   繁体   English

HTML 辅助功能选项卡无法按预期工作

[英]HTML Accessibility tab not works as expected

I have a form with 3 input element.我有一个带有 3 个input元素的表单。 the accessibility team requires to focus the element on tab press .可访问性团队需要将元素集中在tab press it works well.它运作良好。 event doing well by shift+tab as well.事件通过shift+tab也做得很好。 but the issue is after the submit button reached by focus they want to continue from first input element instead of leaving the page and focusing the address bar.但问题是在焦点到达提交按钮后,他们希望从第一个输入元素继续,而不是离开页面并聚焦地址栏。

Is it possible?是否可以? how can i make focus to loop my form in tab and shif+tab instead of moving out?我怎样才能让焦点在tabshif+tab循环我的表单而不是移出?

I am showing the form in popup modal.我在popup模式中显示表单。

 <form action="/action_page.php"> <label for="fname">First name:</label><br> <input tabindex="1" type="text" id="fname" name="fname" value="John"><br> <label for="lname">Last name:</label><br> <input tabindex="2" type="text" id="lname" name="lname" value="Doe"><br><br> <input tabindex="3" type="submit" value="Submit"> </form>

  1. Does this popup appear on page load or is it activated using a button on the page?这个弹出窗口是在页面加载时出现还是使用页面上的按钮激活? => button click show the popup( for confirm ) =>按钮单击显示弹出窗口(用于确认)
  2. Where is the popup located within the DOM - is it within a / etc. or is it outside of the document flow?弹出窗口位于 DOM 中的什么位置 - 是在 / 等内还是在文档流之外? => within dom (placed as angular component ) =>在 dom 内(作为角度分量放置)

2a. 2a. If it is within the / etc. are you able to move it outside of that.如果它在 / 等范围内,您是否可以将其移到该范围之外。 => it's sitting outside out it already. =>它已经坐在外面了。 because the popup page based因为弹出页面基于

  1. Do they want a fully accessible version or is tab the only requirement (as screen reader users do not tend to use tab to navigate, instead using shortcuts for headings, links, forms mode etc.).他们想要一个完全可访问的版本还是选项卡是唯一的要求(因为屏幕阅读器用户不倾向于使用选项卡进行导航,而是使用标题、链接、表单模式等的快捷方式)。 Sorry lots of questions just need to know how in-depth to go in answer.抱歉,很多问题只需要知道回答的深度即可。 => required as fully accessible =>需要完全可访问

Thanks for answering the questions, hopefully the following explanation will highlight why I was asking them (and then I will offer some solutions).感谢您回答问题,希望以下解释能突出我问他们的原因(然后我将提供一些解决方案)。

Why can't we just intercept the tab key?为什么我们不能截取tab键?

Screen reader users don't navigate using only the tab key.屏幕阅读器用户不会仅使用 Tab 键进行导航。 Depending on the screen reader they use they use different shortcuts to navigate via headings, links, forms etc.根据他们使用的屏幕阅读器,他们使用不同的快捷方式通过标题、链接、表单等进行导航。

This causes accessibility issues with popups as people only tend to capture the tab key.这会导致弹出窗口的可访问性问题,因为人们只倾向于捕获Tab键。 Then if a user uses a shortcut, eg 2 in NVDA to jump through heading level 2s on the page they can end up outside of the modal without knowing it exists, often without any way to get back into the modal without tabbing around for ages.然后,如果用户使用快捷方式,例如 NVDA 中的2跳过页面上的标题级别 2,他们可能会在不知道它存在的情况下结束模态,通常没有任何方法可以回到模态而不用长时间切换。

So the solution is obvious, make sure nothing else on the page is accessible (not just not focusable).所以解决方案很明显,确保页面上没有其他内容可访问(不仅仅是不可聚焦)。

However you need to have your DOM structure well ordered / organised to make this manageable.但是,您需要对 DOM 结构进行良好的排序/组织以使其易于管理。

Problems to solve需要解决的问题

  1. Screen reader users can access non-focusable elements屏幕阅读器用户可以访问不可聚焦的元素
  2. They could change their shortcut keys so we can't rely on intercepting key presses to try and fix the problem.他们可以更改快捷键,因此我们不能依靠拦截按键来尝试解决问题。
  3. We want to maintain the same visual design (ie we can't just use display:none on all other elements).我们希望保持相同的视觉设计(即我们不能只在所有其他元素上使用display:none )。
  4. We want a pattern we can repeat so we can't just individually hide elements on the page.我们想要一个可以重复的模式,这样我们就不能单独隐藏页面上的元素。
  5. We want to manage focus correctly so that when the modal is closed it reverts focus back to the previous item (in your circumstances).我们希望正确管理焦点,以便在模式关闭时将焦点恢复到上一项(在您的情况下)。
  6. We want to loop back to the first item in the modal upon reaching the last item (we can do this intercepting the tab key as we can't cover all scenarios, neither do we want to as that would cause more accessibility issues.)我们希望在到达最后一项时循环回到模态中的第一项(我们可以拦截tab键,因为我们无法覆盖所有场景,我们也不希望这样做,因为这会导致更多的可访问性问题。)

Solution解决方案

problems 1, 2, 3 and 4问题 1、2、3 和 4

As we cannot intercept key presses to manage focus within the modal we have to make every other element (other than those in the modal) completely inaccessible while the modal is active.由于我们无法在模态中拦截按键来管理焦点,因此我们必须在模态处于活动状态时使所有其他元素(除了模态中的元素)完全无法访问。

aria-hidden="true" is effectively display: none for screen readers. aria-hidden="true"有效地display: none用于屏幕阅读器。 Support for aria-hidden is good at around 90% to 95% for all screen reader / browser combos.对于所有屏幕阅读器/浏览器组合,对aria-hidden支持大约为 90% 到 95%。

To make the content outside of the modal inaccessible we need to add aria-hidden="true" to every element outside of the modal as well as tabindex="-1" to ensure that nothing can be focused outside of the modal using the tab key.为了使模态之外的内容无法访问,我们需要向模态外的每个元素添加aria-hidden="true"以及tabindex="-1"以确保使用选项卡不会将任何内容聚焦在模态之外钥匙。

I asked about your document structure as the easiest way to implement this is on regions / main landmarks.我询问了您的文档结构,因为实现这一点的最简单方法是在区域/主要地标上。

So when the modal is active we need to add aria-hidden="true" and tabindex="-1" to the <head> , <main> , <footer> etc. By doing it at the landmark level and by putting the modal outside of the main document flow this becomes easy to manage and maintain while preserving semantic HTML markup.因此,当模态处于活动状态时,我们需要将aria-hidden="true"tabindex="-1"<head><main><footer>等。通过在地标级别执行此操作并将在主文档流之外使用模态,这变得易于管理和维护,同时保留语义 HTML 标记。 The opposite is true of the modal (so hide it using the same technique when it isn't active.)模态的情况正好相反(所以当它不活动时使用相同的技术隐藏它。)

Before modal open模态打开前

<head aria-hidden="false"></head>
<main aria-hidden="false"></main>
<footer aria-hidden="false"></footer>
<div class="modal" aria-hidden="true" tabindex="-1"></div>

Modal open模态打开

<head aria-hidden="true" tabindex="-1"></head>
<main aria-hidden="true" tabindex="-1"></main>
<footer aria-hidden="true" tabindex="-1"></footer>
<div class="modal" aria-hidden="false"></div>

Note how I have aria-hidden always added as some screen readers do not react well to dynamic addition of aria (they react fine to changing properties though).请注意我是如何始终添加aria-hidden因为某些屏幕阅读器对aria动态添加反应不佳(尽管它们对更改属性反应良好)。

Points 5 and 6第 5 点和第 6 点

For this I think it will be easiest to share the code I use to trap focus within a modal.为此,我认为最容易分享我用来在模态中捕获焦点的代码。

The purpose of the below function is to focus the first focusable item within a modal when it opens, store a reference to the element that activated the modal (as we want to return the user there when the modal closes) and to manage focus.以下函数的目的是在模态打开时将第一个可聚焦项聚焦,存储对激活模态的元素的引用(因为我们希望在模态关闭时将用户返回到那里)并管理焦点。

Please note that I use a micro library to enable jQuery style selectors so you may need to tweak things for your use.请注意,我使用了一个微型库来启用 jQuery 样式选择器,因此您可能需要调整一些东西以供您使用。

Managing focus explanation and code管理焦点解释和代码

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变量是模态的类名,因此您可以针对不同的模态。

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是一个全局变量数组,因此可以替换为从函数返回结果。

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 could use an ID instead). setFocus函数在模态打开时调用,传递按下以激活它的元素和模态的className (更适合我们的用例,您可以使用 ID 代替)。

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

kluio.helpers.setFocus = function (item, className) { //we pass in the button that activated the modal and the className of the modal, your modal must have a unique className for this to work.

    className = className || "content"; //defaults to class 'content' in case of error ("content" being the class on 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, you may be able to omit this.
            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.然后我们使用以下函数拦截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 / button.最后,在您的 closeAllModals 函数版本中,您需要将焦点返回到引用元素/按钮。

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

The line kluio.globalVars.canFocus[0].focus();kluio.globalVars.canFocus[0].focus(); is called to set focus to the first focusable item within the modal once it is activated, you shouldn't need to tab into the first element when it opens it should be automatically focused.被调用以将焦点设置到模态中的第一个可聚焦项,一旦它被激活,当它打开时,您不需要 Tab 进入第一个元素,它应该自动聚焦。

Point 5 is covered by the line kluio.globalVars.beforeOpen = item;第 5 点被kluio.globalVars.beforeOpen = item;行覆盖kluio.globalVars.beforeOpen = item; to set a reference to the item that opened the modal and kluio.globalVars.beforeOpen.focus();设置对打开模态和kluio.globalVars.beforeOpen.focus();的项目的引用kluio.globalVars.beforeOpen.focus(); within the close function to return focus to that item.在 close 函数中将焦点返回到该项目。

Point 6 is covered within the document.onkeydown function starting at if (kluio.globalVars.modalOpen && evt.keyCode == 9) { .第 6 点包含在document.onkeydown函数中,从if (kluio.globalVars.modalOpen && evt.keyCode == 9) {

I hope all of the above is clear, any questions just ask, if I have time later I will turn it all into a fiddle.我希望以上所有内容都清楚,任何问题都可以问,如果以后有时间我会全部变成小提琴。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM