简体   繁体   English

将初始选项卡焦点设置在新创建的元素上,而不会弄乱屏幕阅读器

[英]setting initial tab focus on newly created element without messing up screen readers

When inserting new html into a section, I want the first tab press to skip the first few links and focus on a later link. 当将新的html插入到节中时,我希望按Tab的第一位跳过前几个链接,而将重点放在后面的链接上。 Currently, my solution is to insert an empty <span> with tabindex='-1' , and then to call focus() on it. 当前,我的解决方案是插入一个带有tabindex='-1'的空<span> ,然后在其上调用focus() However, I noticed that screen-reading software will jump to this focus() . 但是,我注意到屏幕阅读软件将跳至该focus() Is there another way to set the initial tab focus, or to make screen-reading software ignore the focus() ? 还有另一种设置初始标签焦点或使屏幕阅读软件忽略focus()吗? (With NVDA, the div I'm inserting into is a role='status' which should be read whenever it updates, and the focus() grabs NVDA away about 40% of the time, without any seeming pattern.) (使用NVDA时,我要插入的div是一个role='status' ,每当更新时都应读取该值,并且focus()大约有40%的时间将NVDA抢走了,没有任何看似的模式。)

A method that failed is tabindex . 失败的方法是tabindex Both Firefox and Chrome don't respect tabindex for the first tab press for inserted elements. Firefox和Chrome浏览器都不会在插入元素的第一次Tab键按下时使用tabindex In the code sample below, the second element has the last tabindex, and yet is focused first in Firefox. 在下面的代码示例中,第二个元素具有最后一个tabindex,但在Firefox中却是第一个重点。 Behavior in Firefox differs between the first tab press and subsequent tab presses. Firefox的行为在第一次按Tab和随后按Tab时有所不同。 Chrome ignores the tabindex completely for the first tab focus, so the first tab focus is always the first link. Chrome会完全忽略第一个标签焦点的tabindex,因此第一个标签焦点始终是第一个链接。

 <!DOCTYPE html> <html> <head> </head> <body> <script> function k() { document.getElementById("h").innerHTML = "<button tabindex='2' onclick='k()'>first</button><button tabindex='3' onclick='k()'>second</button><button tabindex='1' onclick='k()'>third</button>"; } </script> <div id="h"><button onclick='k()'>click me</button></div> </body> </html> 

I also tried marking the empty <span> with aria-hidden='true' but that didn't help. 我也尝试用aria-hidden='true'标记空的<span> ,但这无济于事。

Attempt 1: From testing, if the DOM element that owns the existing focus is destroyed, the next object to receive a tab's focus is erratic, and behaves differently on Firefox and Chrome. 尝试1:从测试开始,如果拥有现有焦点的DOM元素被破坏,则下一个获得标签焦点的对象将不稳定,并且在Firefox和Chrome上的行为将有所不同。

On Firefox, the focus is "ghostly shifted" to the first text-order element to appear, and then the first tab will shift forward and backward from this first element. 在Firefox上,焦点将“鬼移”到出现的第一个文本顺序元素,然后第一个选项卡将从该第一个元素向前和向后移动。 So a tab will reach the element whose tab order is after the first element, and a shift tab will reach the element whose tab order is before the first element. 因此,制表符将到达其制表符顺序在第一个元素之后的元素,而移位制表符将到达其制表符顺序在第一个元素之前的元素。

On Chrome, the first tab's focus will appear on the first text-order element no matter what tabindex is. 在Chrome上,无论tabindex是什么,第一个标签的焦点都将出现在第一个文本顺序元素上。

That means that tabindex is a nonworking solution if the DOM element is destroyed. 这意味着,如果DOM元素被破坏,则tabindex是无效的解决方案。

Attempt 2: The alternative is focus(). 尝试2:替代方法是focus()。 Inserting a ghost element with tabindex='-1' style='outline:none', and then calling focus() on it, does make tab focus on the element I want it to focus on. 插入一个具有tabindex ='-1'style ='outline:none'的ghost元素,然后对其调用focus(),确实会使Tab键聚焦在我希望它聚焦的元素上。 However, this has the problem of screwing up screenreaders. 但是,这存在拧紧屏幕阅读器的问题。 Whenever focus() is called, a screenreader (NVDA tested) might do one of three things: 每当调用focus()时,屏幕阅读器(已通过NVDA测试)可能会执行以下三种操作之一:

  1. read the new message text like I want it to (20% chance) 像我希望的那样阅读新的消息文本(20%的机会)
  2. read the Window title, then tab title, then the focus()d element, which is horrible (70% chance) 读取窗口标题,然后标签标题,然后是focus()d元素,这很可怕(70%的机会)
  3. read nothing at all (10% chance) 完全不阅读(10%的机会)

aria-hidden doesn't help. 隐藏的咏叹调没有帮助。 autofocus does nothing. 自动对焦不执行任何操作。

Attempt 3: That means focus() is not an acceptable solution. 尝试3:这意味着focus()不是可接受的解决方案。 So the only alternative is to not destroy the DOM element. 因此,唯一的选择是不破坏DOM元素。 So the DOM element must be moved. 因此,必须移动DOM元素。 However, the moved-element graveyard will fill up if we continually push things there. 但是,如果我们不断将东西推向那里,那么移动的墓地就会填满。 And we can't delete a graveyard element if it contains our focus element, or else we'll be in the destroyed-focus-element situation. 而且,如果墓地元素包含我们的焦点元素,我们将无法删除它,否则我们将处在被破坏的焦点元素的情况下。 In my situation, interactive fiction will fill this graveyard up to gigabytes in a few hours. 在我的情况下,互动小说将在几个小时内将这个墓地填满至数十亿字节。 Thus, when deleting history log elements, we must check the element and all its children to make sure focus is not contained there, and then dance around it if it is. 因此,在删除历史日志元素时,我们必须检查该元素及其所有子元素,以确保焦点不包含在其中,然后在焦点周围跳舞。

Attempt 4: However, it turns out that moving an element kills its focus anyway (at least on Firefox). 尝试4:但是,事实证明,移动元素无论如何都会杀死其焦点(至少在Firefox上如此)。 So you can't just move it to a graveyard, you have to not touch it at all. 因此,您不能仅将其移至墓地,而不必触摸它。

Once you have a surviving object that you haven't moved anywhere, you need to set tabindex='-1' on it, or else this graveyard object will mess with your tab order. 一旦有一个尚存的对象没有移到任何地方,就需要在其上设置tabindex ='-1',否则此墓地对象会干扰您的选项卡顺序。 However, if you do set its tabindex to -1, then (at least on Firefox), tab order now behaves like the destroyed-DOM-object situation once again. 但是,如果您确实将其tabindex设置为-1,那么(至少在Firefox上),选项卡顺序现在再次表现为销毁DOM对象的情况。

Attempt 5: 尝试5:

  1. don't move that disappearing object anywhere! 不要将消失的物体移到任何地方!
  2. instead, take that object, and then hide it. 取而代之的是,拿走那个物体,然后将其隐藏。
  3. build your new object around it: the old object must be placed exactly where you want the tab placement to be, in text order. 在其周围构建新对象:必须按照文本顺序将旧对象准确放置在希望标签位置的位置。 Your new content will be half before it and half after it. 您的新内容将是之前的一半,之后的一半。
  4. check all of the hidden object's subnodes (recursively) for activeElement to find out where its focus is. (递归地)检查所有隐藏对象的子节点的activeElement,以找出其焦点在哪里。 For every non-active element that isn't a parent of the node with focus, you must delete it or else the screen reader will complain a lot. 对于不是具有焦点的节点的父级的每个非活动元素,必须将其删除,否则屏幕阅读器会抱怨很多。 For the surviving nodes, make sure they are completely invisible and have no content, but don't use display:none, that will destroy the focus. 对于尚存的节点,请确保它们完全不可见且不包含任何内容,但不要使用display:none,这会破坏焦点。 Set tabindex = -1 on the focused node. 在焦点节点上设置tabindex = -1。
  5. If your focus wasn't in the object you deleted, then find the object that owns the focus and set its tabindex to between the tabindex of the first half and second half. 如果焦点不在删除的对象中,则找到拥有焦点的对象,并将其tabindex设置在上半部分和下半部分的tabindex之间。

I have run out of patience, and I am not going to implement this proposed solution, leaving mysteriously half-deleted, half-hidden elements in the middle of new text. 我已经忍耐不住了,我不会实施这个建议的解决方案,而是在新文本中间保留了一半被删除,一半被隐藏的元素。 After 5 failed attempts, I don't have much hope left, and I don't want to saddle maintainers with pages of in-depth comments, strange unintuitive behavior, and unexpected performance concerns, just for screenreaders. 经过5次失败的尝试后,我没有太多希望了,我也不想让维护者在屏幕阅读器页面上看到深入评论,奇怪的不直观行为以及意外的性能问题。 I am going to stick with my old focus() solution. 我将继续使用我以前的focus()解决方案。

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

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