我意识到这可能是一个可访问性问题,最好不要管它,但我想弄清楚是否有可能阻止标签在标签循环中访问地址栏。
我的应用程序有另一种循环输入区域的方法,但是许多新用户本能地尝试使用选项卡,但它没有按预期工作。
我意识到这可能是一个可访问性问题,最好不要管它,但我想弄清楚是否有可能阻止标签在标签循环中访问地址栏。
我的应用程序有另一种循环输入区域的方法,但是许多新用户本能地尝试使用选项卡,但它没有按预期工作。
这是一个通用的 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()
我曾经在 tabindex 1 和最后一个 tabindex 上添加两个微小的、不可见的元素。为这两个添加一个 onFocus:tabindex 为 1 的元素应该聚焦最后一个真实元素,具有 max tabindex 的元素应该聚焦第一个真实元素。确保将第一个真实元素集中在 Dom:loaded 上。
您可以使用 Javascript 并在具有最高“tabindex”的元素上捕获“keydown”事件。如果用户在没有“Shift”键(event.shiftKey == false)的情况下按下“TAB”键(event.keyCode==9),那么只需将焦点设置在具有最低tabindex的元素上。
然后,您还需要对 tabindex 最低的元素执行相同的操作。捕获此元素的“keydown”事件。如果用户使用“Shift”键 (event.shiftKey == true) 按下“TAB”键 (event.keyCode==9),则将焦点设置在具有最高 tabindex 的元素上。
这将有效地防止地址栏使用 TAB 键聚焦。我在我当前的项目中使用这种技术。
如果按下正确的组合键,不要忘记取消 keydown 事件!对于 JQuery,它是“event.preventDefault()”。在标准 Javascript 中,我相信您只是“返回 false”。
这是我正在使用的一个包含 JQuery 的片段......
$('#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 的索引。
tabindex
您可以使用 global属性来控制 Tab 键的顺序(以及哪些元素应该能够获得焦点)。
但是,您不能阻止用户使用此属性进入另一个不受页面控制的上下文(例如浏览器的地址栏)。(不过,它可能与 JavaScript 结合使用。)
对于这样的(邪恶的!)用例,您必须查看键盘陷阱。
WCAG 2.0 有指导方针:2.1.2 No Keyboard Trap。在了解 SC 2.1.2中,您可以找到本指南的“技术和故障”:
所以,也许你会从中得到一些想法,这样一个陷阱是如何可能的。
嗨,我有一个简单的解决方案。只需在页面末尾放置一个空跨度。给它一个 id 和 tabindex = 0,给这个跨度一个 onfocus 事件,当触发时让你的焦点跳转到你想要循环通过的页面上的第一个元素。这样您就不会失去对文档的关注,因为如果您这样做,您的事件将不再起作用。
Salinan 解决方案对我有用 将其放在 html 页面的开头:
<span tabindex="0" id="prevent-outside-tab"></span>
这在你的 html 页面的末尾。:
<span tabindex="0" onfocus="foucsFirstElement()"></span>
foucsFirstElement() :
foucsFirstElement() {
document.getElementById("prevent-outside-tab").focus();
},
不确定这是否仍然是一个问题,但我实现了自己的不使用 jQuery 的解决方案,可以在所有元素都有 tabindex="0" 的情况下使用,并且当 DOM 可能发生变化时。如果您想将 tabcycling 限制为包含 tabindex 元素的特定元素,我为上下文添加了一个额外的参数。
关于论点的一些简要说明:
min必须小于或等于max,并且contextSelector是一个可选字符串,如果使用它应该是一个有效的选择器。如果contextSelector是无效选择器或与任何元素都不匹配的选择器,则将文档对象用作上下文。
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,则制表符将自然循环,直到达到最小值或最大值。如果向后跳格并达到最小值,或者向前跳格并达到最大值,则跳格将分别循环到最小元素或最大元素。
示例用法:
// 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');
我使用了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 对象、选择器甚至是document,或者您可以省略它。
当然,滚动动画是可选的。