限制tabindex聚焦到页面的一部分 [英] Restrict tabindex focusing to a section of the page
问题描述
问题: 打开模式窗口时,只有窗口处于活动状态,页面的其余部分无法通过鼠标访问,但可通过从模式窗口中退出来访问元素。 问题: 如何通过使用tab按钮仅限表单窗口中的元素来限制移动? 我唯一能想到的就是使用Javascript在所有表单元素上设置 不,这是唯一的方法。 下面是一个快速演示: † 我们寻找 请参阅 Situation: I have a webpage which opens modal windows (light boxes) which contain forms where the user can input data. Users generally navigate using the keyboard, tabbing from one field to the next. Problem: When a modal window opens, only the window is active, the rest of the page is not accessible using the mouse, but elements can be reached by tabbing out of the modal window. Question: How can I restrict movement by using the tab button to only the elements within the form window? The only thing I can think of is using Javascript to set No, it's the only way. Here's a quick demo:
† We look for Here's a demo which uses data attributes to store the original
See 这篇关于限制tabindex聚焦到页面的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
$ b
tabindex = -1
当模态窗口打开时,然后在模态窗口关闭时将 tabindex
值设置回它们以前的值。
是否有更简单/更好的方法?
$ b
tabIndex
大于 -1 $ c的元素$ c> † 并且不属于您的模式。 创建数组‡ 每个元素及其原始
tabIndex
。
tabIndex
设置为 -1
因此它不能再从键盘获得焦点。
tabIndex
。
函数isDescendant(ancestor,descendant){do {if(descendant === ancestor)return true; } while(descendant = descendant.parentNode);返回false;} var tabIndexRestoreFunctions; var lastFocused; document.getElementById(btn-show-modal)。addEventListener(click,function(e){lastFocused = document.activeElement; var modal = document.querySelector(。modal ); tabIndexRestoreFunctions = Array.prototype //获得不是我们模态子项的tabable项目(document.all,o => o.tabIndex> -1&&!isDescendant(modal, o))//遍历这些项目,设置tabIndex为-1,//返回一个函数来恢复tabIndex .map(o => {var oldTabIndex = o.tabIndex; o.tabIndex = -1; return )=> o.tabIndex = oldTabIndex;}); // show modal modal.classList.add(shown); // focus modal autofocus modal.querySelector([autofocus])。focus();}) ; document.getElementById(btn-close-modal)。addEventListener(click,function(e){// restore tabs tabIndexRestoreFunctions&&&&& tabIndexRestoreFunctions.forEach(f => f()); tabIndexRestoreFunctions = null ; //隐藏模式文档nt.querySelector( 模态 )classList.remove( 示出); //恢复焦点lastFocused&&
.modal {显示:无;位置:固定; top:0;正确:0;底部:0;左:0; background-color:rgba(128,128,128,.75);} .modal.shown {display:flex;} .modal-content {margin:auto;宽度:500px;填充:30px; border:1px solid#333;
< label> test< input autofocus />< / label><按钮>虚拟按钮< /按钮>< hr /><按钮id =btn-show-modal>打开模式< /按钮><< ; div class =modal> < div class =modal-content> < label>测试<输入自动对焦/> < /标签> < button id =btn-close-modal>关闭模式< / button> < / div>< / div>
tabIndex> -1
,这样我们就可以专注于tabable元素。您可以进一步限制该过滤器忽略隐藏的元素,但我会将其留给您。在这两种情况下,列表都不应该很大。另外,如在演示中,您可以使用一系列函数填充数组,其唯一目的是重置 tabIndex
。您也可以完全放弃数组,并简单地向受影响的元素添加 data-original-tab-index
属性...使用 document.querySelectorAll [data-original-tab-index])
以在事实之后检索它们。 数据属性来存储原始的 tabIndex
,所以你不必维护自己的数组:
函数isDescendant(ancestor,descendant){do {if(descendant === ancestor)return true; } while(descendant = descendant.parentNode);返回false;} var lastFocused; document.getElementById(btn-show-modal)。addEventListener(click,function(e){lastFocused = document.activeElement; var modal = document.querySelector(。modal); Array.prototype.forEach.call(document.all,o => {if(o.tabIndex> -1&&!isDescendant(modal,o)){o.dataset.originalTabIndex = o.tabIndex; o .tabIndex = -1;}}); // show modal modal.classList.add(shown); // focus modal autofocus modal.querySelector([autofocus])。focus();}); document。 getElementById(btn-close-modal)。addEventListener(click,function(e){// restore tabs Array.prototype.forEach.call(document.querySelectorAll([data-original-tab-index]) ,o => {o.tabIndex = o.dataset.originalTabIndex; delete o.dataset.originalTabIndex;}); // hide modal document.querySelector(。modal)。classList.remove(shown); / restore focus lastFocused&& lastFocused.focus();});
.modal {display:none;位置:固定; top:0;正确:0;底部:0;左:0; background-color:rgba(128,128,128,.75);} .modal.shown {display:flex;} .modal-content {margin:auto;宽度:500px;填充:30px; border:1px solid#333;
< label> test< input autofocus />< / label><按钮>虚拟按钮< /按钮>< hr /><按钮id =btn-show-modal>打开模式< /按钮><< ; div class =modal> < div class =modal-content> < label>测试<输入自动对焦/> < /标签> < button id =btn-close-modal>关闭模式< / button> < / div>< / div>
HTMLElement。数据集
tabindex=-1
on all form elements (and other focusable elements) when the modal window is opened and then set the tabindex
values back to their previous values when the modal window is closed.
Is there a simpler/better way?
tabIndex
greater than -1
† and don't belong to your modal.tabIndex
.tabIndex
to -1
so it can no longer receive focus from the keyboard.tabIndex
.function isDescendant(ancestor, descendant) {
do {
if (descendant === ancestor) return true;
} while (descendant = descendant.parentNode);
return false;
}
var tabIndexRestoreFunctions;
var lastFocused;
document.getElementById("btn-show-modal").addEventListener("click", function(e) {
lastFocused = document.activeElement;
var modal = document.querySelector(".modal");
tabIndexRestoreFunctions = Array.prototype
// get tabable items which aren't children of our modal
.filter.call(document.all, o => o.tabIndex > -1 && !isDescendant(modal, o))
// iterate over those items, set the tabIndex to -1, and
// return a function to restore tabIndex
.map(o => {
var oldTabIndex = o.tabIndex;
o.tabIndex = -1;
return () => o.tabIndex = oldTabIndex;
});
// show modal
modal.classList.add("shown");
// focus modal autofocus
modal.querySelector("[autofocus]").focus();
});
document.getElementById("btn-close-modal").addEventListener("click", function(e) {
// restore tabs
tabIndexRestoreFunctions && tabIndexRestoreFunctions.forEach(f => f());
tabIndexRestoreFunctions = null;
// hide modal
document.querySelector(".modal").classList.remove("shown");
// restore focus
lastFocused && lastFocused.focus();
});
.modal {
display: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(128, 128, 128, .75);
}
.modal.shown {
display: flex;
}
.modal-content {
margin: auto;
width: 500px;
padding: 30px;
border: 1px solid #333;
background-color: #fdfdfd;
}
<label>test
<input autofocus />
</label>
<button>dummy button</button>
<hr/>
<button id="btn-show-modal">open modal</button>
<div class="modal">
<div class="modal-content">
<label>test
<input autofocus />
</label>
<button id="btn-close-modal">close modal</button>
</div>
</div>
tabIndex > -1
so that we can focus specifically on tabable elements. You could further restrict that filter to ignore hidden elements, but I'll leave that to you. In either case, the list shouldn't be very big.
‡ Alternatively, as in the demo, you could fill the array with a series of functions whose sole purpose is to reset tabIndex
. You could also forego the array entirely and simply add a data-original-tab-index
attribute to the affected elements... using document.querySelectorAll("[data-original-tab-index]")
to retrieve them after the fact.tabIndex
so you don't have to maintain your own array:function isDescendant(ancestor, descendant) {
do {
if (descendant === ancestor) return true;
} while (descendant = descendant.parentNode);
return false;
}
var lastFocused;
document.getElementById("btn-show-modal").addEventListener("click", function(e) {
lastFocused = document.activeElement;
var modal = document.querySelector(".modal");
Array.prototype.forEach.call(document.all, o => {
if (o.tabIndex > -1 && !isDescendant(modal, o)) {
o.dataset.originalTabIndex = o.tabIndex;
o.tabIndex = -1;
}
});
// show modal
modal.classList.add("shown");
// focus modal autofocus
modal.querySelector("[autofocus]").focus();
});
document.getElementById("btn-close-modal").addEventListener("click", function(e) {
// restore tabs
Array.prototype.forEach.call(document.querySelectorAll("[data-original-tab-index]"), o => {
o.tabIndex = o.dataset.originalTabIndex;
delete o.dataset.originalTabIndex;
});
// hide modal
document.querySelector(".modal").classList.remove("shown");
// restore focus
lastFocused && lastFocused.focus();
});
.modal {
display: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(128, 128, 128, .75);
}
.modal.shown {
display: flex;
}
.modal-content {
margin: auto;
width: 500px;
padding: 30px;
border: 1px solid #333;
background-color: #fdfdfd;
}
<label>test
<input autofocus />
</label>
<button>dummy button</button>
<hr/>
<button id="btn-show-modal">open modal</button>
<div class="modal">
<div class="modal-content">
<label>test
<input autofocus />
</label>
<button id="btn-close-modal">close modal</button>
</div>
</div>
HTMLElement.dataset