最简单的方法只能通过特定元素的可聚焦后裔制表? [英] Simplest way to tab only through focusable descendants of a particular element?
问题描述
< input type =text>
), tabindex =0
之类的。 现在让我们来说说我想要的文档的一部分显示为模式对话框,我不希望用户被对话框外的任何东西分心。我希望tab键只能通过对话框的容器元素内的可聚焦元素循环。什么是最简单的方法来做到这一点?
如果可能的话,我正在寻找一个解决方案,不关心对话框的内容或页面的其余部分是和不会尝试修改它们。也就是说,例如,我不想让对话框外的元素不可聚焦。首先,这需要做出可逆的变化,并追踪状态。其次,这需要知道一个元素可以被聚焦的所有可能的方式。这感觉凌乱,脆弱,无法对我。
我的第一次尝试看起来像这样,但只能在向前的方向(按Tab键)。它不能在反方向工作(按住Shift + Tab键)。
< div>可对焦的内容。 < / DIV>
< div class =dialogtabindex =0>
<! - 焦点应该在打开的时候被困在这个对话框中 - >
< div class =content>
在这里表达内容和可聚焦的东西。
< / div>
< div class =last-focustabindex =0onfocus =this.parentNode.focus()>< / div>
< / div>
< div>对话框外部的可聚焦内容。< / div>
我宁愿看纯JavaScript解决方案。如果有这样的一个库,如jQuery这样做,我宁愿链接到库代码,这样做。
为了完整起见,我将链接指向 jQuery UI对话框,由@Domenic提供并填写详细信息。为了实现这个jQuery时尚需要两个事情:
$ b
-
听取
标签
或Shift + Tab
(在keydown
),以便应该捕捉焦点的模态元素。这是通过键盘移动焦点的唯一手段。 (如果要防止鼠标与文档的其余部分交互,这是一个单独的问题,通过覆盖元素来解决,以防止任何鼠标事件通过。) -
找到模态元素中的所有可放置元素。这些是所有可聚焦元素的子集,不包括那些具有
tabindex = - 1
。
Tab
前进。 Shift + Tab
往后退。任何时候按下 Tab键
,当模态元素中的最后一个tabbable元素被关注时,第一个应该获得焦点。同样的,任何时候 Shift + Tab
都会在第一个tabbable元素被关注的时候被按下,最后一个应该会获得焦点。这将保持焦点内的模态元素。
困难的部分是知道哪些元素是可tabbable。因为tabbable元素都是没有 tabindex = - 1
的可聚焦元素,所以我们需要知道哪些元素是可聚焦的。由于没有属性来确定元素是否可以聚焦,jQuery通过对以下情况进行硬编码:
输入
, select
, textarea
,按钮
和元素
a
和区域
具有 href
的元素,或者为 tabindex
set设置一个数值。
tabindex
set的数值的任何元素。
检查这三种情况是不够的。 jQuery继续确保元素是可见的。这意味着以下两个都必须是真的:
- 没有祖先是
display:none $ c
visibility 的计算值是visible
。这意味着具有visibility 集合的最近的祖先必须具有
visible
的值。如果没有祖先的visibility
set,那么计算的值是visible
。
ul>
需要注意的是, jQuery的:visible
选择器对于这个实现看起来不正确,因为它表示具有 visibility:hidden
...的元素被认为是可见的,但它们不是可以调整的。
Let's say I have a document full of focusable elements, either because they are innately focusable (like <input type="text">
) or because they have tabindex="0"
or the like.
Now let's say there's a section of my document that I want to display as a modal dialog box, and I don't want the user to be distracted by anything outside the dialog box. I would like for the tab key to cycle only through focusable elements inside the container element for the dialog box. What is the simplest way to do this?
If possible, I am looking for a solution that doesn't care what the contents of the dialog or the rest of the page are and doesn't try to modify them. That is, I don't want to make the elements outside of the dialog not focusable, for example. First, this requires making a reversible change and keeping track of state. Second, this requires knowing all the possible ways an element could be made focusable. This feels messy, fragile, and unscalable to me.
My first attempt looks like this, but works only in the forward direction (pressing Tab). It doesn't work in the reverse direction (pressing Shift+Tab).
<div>Focusable stuff outside the dialog.</div>
<div class="dialog" tabindex="0">
<!-- Focus should be trapped inside this dialog while it's open -->
<div class="content">
Form contents and focusable stuff here.
</div>
<div class="last-focus" tabindex="0" onfocus="this.parentNode.focus()"></div>
</div>
<div>More focusable stuff outside the dialog.</div>
I'd rather see pure JavaScript solutions. If there is a means of doing this with a library such as jQuery, I would prefer a link to the library code that does this.
In the interest of completeness, I'm taking the link to jQuery UI dialog that @Domenic provided and filling in the details.
To implement this in the jQuery fashion requires two things:
Listening for
Tab
orShift+Tab
(onkeydown
) for the modal element that should trap focus. This is the only means of moving focus via the keyboard. (If you want to prevent mouse interaction with the rest of the document, that is a separate problem solved by covering it with an element to prevent any mouse events from getting through.)Finding all tabbable elements inside the modal element. These are a subset of all focusable elements, excluding those that have
tabindex="-1"
.
Tab
goes forward. Shift+Tab
goes backwards. Any time Tab
is pressed while the last tabbable element in the modal element is focused, the first should receive focus. Similarly, any time Shift+Tab
is pressed while the first tabbable element is focused, the last should receive focus. This will keep focus inside the modal element.
The hard part is knowing which elements are tabbable. Since tabbable elements are all focusable elements that don't have tabindex="-1"
, then we need to know know which elements are focusable. Since there's no property to determine if an element is focusable, jQuery does it by hard-coding the following cases:
input
,select
,textarea
,button
, andobject
elements that aren't disabled.a
andarea
elements that have anhref
or have a numerical value fortabindex
set.- any element that has a numerical value for
tabindex
set.
It's not enough to check for these three cases. jQuery goes on to ensure that the element is visible. This means both of the following must be true:
- None of its ancestors are
display: none
. - The computed value of
visibility
isvisible
. This means that the nearest ancestor to havevisibility
set must have a value ofvisible
. If no ancestor hasvisibility
set, then the computed value isvisible
.
It should be noted that jQuery's :visible
selector does not look correct for this implementation because it says "elements with visibility: hidden
…are considered to be visible," but they are not focusable.
这篇关于最简单的方法只能通过特定元素的可聚焦后裔制表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!