阻止选项卡在地址栏中循环

时间:2013-03-12 07:56:51

标签: browser user-interface accessibility

我意识到这可能是一个可访问问题,最好不要单独讨论,但我想弄清楚是否有可能阻止标签访问标签周期中的地址栏。

我的应用程序有另一种在输入区域中循环的方法,但许多新用户本能地尝试使用该选项卡,并且它不能按预期工作。

8 个答案:

答案 0 :(得分:6)

这是一个通用的jquery实现,您无需查找最大选项卡索引。请注意,如果您在DOM中添加或删除元素,此代码也将起作用。

$('body').on('keydown', function (e) {
    var jqTarget = $(e.target);
    if (e.keyCode == 9) {

        var jqVisibleInputs = $(':input:visible');
        var jqFirst = jqVisibleInputs.first();
        var jqLast = jqVisibleInputs.last();

        if (!e.shiftKey && jqTarget.is(jqLast)) {
            e.preventDefault();
            jqFirst.focus();
        } else if (e.shiftKey && jqTarget.is(jqFirst)) {
            e.preventDefault();
            jqLast.focus();
        }
    }
});

但是,您应该注意上面的代码仅适用于可见输入。某些元素可能会成为文档的activeElement,即使它们没有输入,所以如果它是你的情况,你应该考虑将它们添加到$(':input:visible')选择器。

我没有添加代码来滚动到焦点元素,因为这可能不是每个人想要的行为......如果你需要它,只需在调用focus()之后添加它

答案 1 :(得分:3)

您可以使用Javascript并捕获" keydown"具有最高" tabindex"的元素上的事件。如果用户按下" TAB" key(event.keyCode == 9)没有" Shift" key(event.shiftKey == false)然后只需将焦点设置在具有最低tabindex的元素上。

对于具有最低tabindex的元素,您还需要反向执行相同的操作。捕捉" keydown"此元素的事件。如果用户按下" TAB" key(event.keyCode == 9)with" Shift" key(event.shiftKey == true)然后将焦点设置在具有最高tabindex的元素上。

这将有效地防止地址栏使用TAB键进行聚焦。我在我当前的项目中使用这种技术。

如果按下正确的按键组合,别忘了取消keydown事件!使用JQuery,它是" event.preventDefault()"。在标准的Javascript中,我相信你只是"返回false"。

这是我使用的JQuery-laden代码段...

    $('#dos-area [tabindex=' + maxTabIndex + ']').on('keydown', function (e) {
        if (e.keyCode == 9 && e.shiftKey == false) {
            e.preventDefault();
            $('#dos-area [tabindex=1]').focus();
        }
    });
    $('#dos-area [tabindex=1]').on('keydown', function (e) {
        if (e.keyCode == 9 && e.shiftKey == true) {
            e.preventDefault();
            $('#dos-area [tabindex=' + maxTabIndex + ']').focus();
        }
    });

另请注意,设置tabindex = 0会对事项的重点顺序产生不良后果。我总是记得(为了我的目的)tabindex是一个基于1的索引。

答案 2 :(得分:2)

您可以使用全局tabindex attribute控制制表顺序(以及哪些元素应该能够获得焦点)。

但是,您无法阻止用户使用此属性切换到不受页面控制的其他上下文(例如浏览器的地址栏)。 (尽管可能与JavaScript结合使用。)

对于这样的(邪恶!)用例,您必须查看键盘陷阱

WCAG 2.0的准则为:2.1.2 No Keyboard Trap。在Understanding SC 2.1.2中,您可以找到本指南的“技巧与失败”:

所以也许你会得到一些关于如何实现这种陷阱的想法。

答案 3 :(得分:1)

我曾经在tabindex 1和最后一个tabindex上添加两个微小的,不可见的元素。为这两个添加onFocus:具有tabindex 1的元素应该聚焦最后一个真实元素,具有max tabindex的元素应该聚焦第一个真实元素。确保将第一个真元素集中在Dom:loaded。

答案 4 :(得分:1)

我使用m-albert解决方案并且它有效。但在我的情况下,我不控制 tabindex 属性。当用户离开页面上的最后一个控件时,我的目的是将焦点设置在页面顶部的工具栏(第一个控件)

$(':input:visible').last().on('keydown', function (e) {
    if (e.keyCode == 9 && e.shiftKey == false) {
        e.preventDefault();
        $('html, body').animate({
            scrollTop: 0
        }, 500);
        $(':input:visible', context).first().focus();
    }
});

context 可以是任何Jquery对象,选择器,甚至是文档,或者您可以省略它。

滚动动画当然是可选的。

答案 5 :(得分:1)

不确定这是否仍然是一个问题,但是我实现了我自己的不使用jQuery的解决方案,可以在所有元素都具有tabindex =“ 0”的情况下使用,并且可以更改DOM。如果要将制表循环限制为包含tabindex元素的特定元素,则为上下文添加了一个额外的参数。

有关参数的一些简短说明:

min 必须小于或等于 max ,并且 contextSelector 是可选字符串,如果使用该字符串应为有效选择器。如果 contextSelector 是无效的选择器或与任何元素都不匹配的选择器,则将 document 对象用作上下文。

function PreventAddressBarTabCyle(min, max, contextSelector) {
    if( isNaN(min) ) throw new Error('Invalid argument: first argument needs to be a number type.')
    if( isNaN(max) ) throw new Error('Invalid argument: second argument needs to be a number type.')
    if( max < min ) throw new Error('Invalid arguments: first argument needs to be less than or equal to the second argument.')
    min = min |0;
    max = max |0;
    var isDocumentContext = typeof(contextSelector) != 'string' || contextSelector == '';

    if( min == max ) {
        var tabCycleListener = function(e) {
            if( e.keyCode != 9 ) return;

            var context = isDocumentContext ? document : document.querySelector(contextSelector);
            if( !context && !('querySelectorAll' in context) ) {
                context = document;
            }

            var tabindexElements = context.querySelectorAll('[tabindex]');
            if( tabindexElements.length <= 0 ) return;
            var targetIndex = -1;
            for(var i = 0; i < tabindexElements.length; i++) {
                if( e.target == tabindexElements[i] ) {
                    targetIndex = i;
                    break;
                }
            }
            // Check if tabbing backward and reached first element
            if( e.shiftKey == true && targetIndex == 0 ) {
                e.preventDefault();
                tabindexElements[tabindexElements.length-1].focus();
            }
            // Check if tabbing forward and reached last element
            if( e.shiftKey == false && targetIndex == tabindexElements.length-1 ) {
                e.preventDefault();
                tabindexElements[0].focus();
            }
        };
    } else {
        var tabCycleListener =  function(e) {
            if( e.keyCode != 9 ) return;

            var context = isDocumentContext ? document : document.querySelector(contextSelector);
            if( !context && !('querySelectorAll' in context) ) {
                context = document;
            }

            var tabindex = parseInt(e.target.getAttribute('tabindex'));
            if( isNaN(tabindex) ) return;
            // Check if tabbing backward and reached first element
            if (e.shiftKey == true && tabindex == min) {
                e.preventDefault();
                context.querySelector('[tabindex="' + max + '"]').focus();
            } 
            // Check if tabbing forward and reached last element
            else if (e.shiftKey == false && tabindex == max) {
                e.preventDefault();
                context.querySelector('[tabindex="' + min + '"]').focus();
            }
        };
    }
    document.body.addEventListener('keydown', tabCycleListener, true);
}

更多说明:

如果 min 等于 max ,则制表符循环自然发生,直到到达上下文中的最后一个元素。如果 min 严格小于 max ,则制表键将自然循环直到达到 min max 。如果向后跳转并达到 min ,或者向前跳转并已达到 max ,则跳转将循环到 min 元素或< strong> max 元素。

用法示例:

// For all tabindex elements inside the document
PreventAddressBarTabCyle(0,0);
// Same as above
PreventAddressBarTabCyle(1,1);
// NOTE: if min == max, the tabindex value doesn't matter
//    it matches all elements with the tabindex attribute

// For all tabindex elements between 1 and 15
PreventAddressBarTabCyle(1,15);
// For tabindex elements between 1 and 15 inside
//   the first element that matches the selector: .some-form
PreventAddressBarTabCyle(1,15, '.some-form');
// For all tabindex elements inside the element
//   that matches the selector: .some-form2
PreventAddressBarTabCyle(1,1, '.some-form2');

答案 6 :(得分:0)

嗨,我有一个简单的解决方案。只需在页面末尾放置一个空的跨度即可。给它一个id和tabindex = 0,给这​​个跨度一个onfocus事件,当触发它时,让您的焦点跳到页面上您想循环通过的低谷。这样一来,您就不会失去对文档的关注,因为如果您这样做了,事件将不再起作用。

答案 7 :(得分:0)

Salinan solution worked for me 把它放在你的 html 页面的开头:

<span tabindex="0" id="prevent-outside-tab"></span>

这在你的 html 页面的末尾。:

<span tabindex="0" onfocus="foucsFirstElement()"></span>

foucsFirstElement() :

foucsFirstElement() {
  document.getElementById("prevent-outside-tab").focus();
},