如何使用正值控制tabIndex和焦点捕获元素?

问题描述 投票:2回答:1

也许这完全是一个坏主意,我很乐意将其作为反馈;但是,我正在寻找一种控制文档上的tabbable元素的好方法。

要求:

  • Api用于控制带有DOM顺序的标签顺序。
  • 聚焦陷阱可能是周期性的,必须明确地转义。
  • 一种将非可列表元素放入制表符流的方法。
  • 写在香草JS。
  • No positive tabIndex values

注意:这是个人思想实验,不确定这是不是一个好主意。将采取任何类型的线索:文章,图书馆,代码片段,但显然最好的将是满足所有要求的答案(或任何其他你可以提出的想法)!

    button {
      padding: 6px 8px;
      margin: 12px;
    }
    
    .focus-trap{
      padding: 24px;
      background: rgba(150, 150, 48, .5);
    }

    
    .now-tabbable {
      display: inline-flex;
      padding: 15px 8px;
      background: pink;
      margin: 12px;
      min-width: 45px;
      justify-content: center;
    }
<!-- 
.focus-traps:

- Are meant to declare that tab focus are order by the programmer.
- Focus-traps can be cyclical. currently denoted by class but up for any ideas data-attr etc.

.now-tabbable:
- Are meant to declare that this element is part of the tab flow.

-->

<div class="focus-trap">
  <button>ZERO &times; escape</button>
  <button>two</button>
  <button>one</button>
  <button>three</button>
  <hr>

  <div class="focus-trap cyclical">
    <h1>Trap  focus in here until escape</h1>
    <button>four - B</button>
    <button>four - C</button>
    <button>four - A &times; escape</button>
  </div>
  <div class="now-tabbable">seven</div>
  <div class="now-tabbable">five</div>
  <div class="now-tabbable">six</div>
</div>
javascript html css accessibility tabindex
1个回答
1
投票

一般来说,你应该避免使用焦点陷阱,除了模态上下文,比如模态对话。

这里建议的解决方案将建立一个带有roving tab index的焦点组,您可以通过箭头键在其中导航焦点。然后TAB将离开该组。

但请记住,您只将焦点组用于可以预期行为的UI模式。 ARIA标准提及Keyboard Navigation Inside Components

[...]强烈建议使用与§ 3. Design Patterns and Widgets中演示的常见GUI操作系统中相似的组件相同的键绑定。

例如,您也可以通过一种明确形成一组的方式直观地格式化按钮,类似于Toolbar

class focusGroup { 
  
  constructor(el, cyclical: false) {
    this.cyclical = cyclical;
    
    // store children sorted by data-tabindex attribute
    this.children = Array.from(el.querySelectorAll('[data-tabindex]')).sort((el1, el2) => el1.getAttribute('data-tabindex') > el2.getAttribute('data-tabindex'));
    
    // remove tab index for all children
    this.children.forEach(childEl => childEl.setAttribute('tabindex', '-1'));
         
    // make first child tabbable
    this.children[0].setAttribute('tabindex', '0');
    this.i = 0;
    
    // bind arrow keys
    el.addEventListener('keyup', e => {
      if (e.key === 'ArrowRight' || e.key === 'ArrowDown') this.next();
      if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') this.prev();
    });
  }
  
  next() {
    if (this.i < this.children.length -1) this.i += 1
    else if (this.cyclical) this.i = 0;
      
    this.updateFocus();
  }
  
  prev() {
    if (this.i > 0) this.i -= 1
    else if (this.cyclical) this.i = this.children.length -1;
    
    this.updateFocus();
  }
  
  updateFocus() {
    this.children.forEach(el => el.setAttribute('tabindex', '-1'));
    this.children[this.i].setAttribute('tabindex', '0');
    this.children[this.i].focus();
  }
} 

document.querySelectorAll('.focus-trap:not(.cyclical)').forEach(el => new focusGroup(el));

document.querySelectorAll('.focus-trap.cyclical').forEach(el => new focusGroup(el, true));
button {
      padding: 6px 8px;
      margin: 12px 0;
    }
    
    .focus-trap{
      padding: 24px;
      background: rgba(150, 150, 48, .5);
    }

    
    .now-tabbable {
      display: inline-flex;
      padding: 15px 8px;
      background: pink;
      margin: 12px;
      min-width: 45px;
      justify-content: center;
    }
<!-- 
.focus-traps:

- Are meant to declare that tab focus are order by the programmer.
- Focus-traps can be cyclical. currently denoted by class but up for any ideas data-attr etc.

.now-tabbable:
- Are meant to declare that this element is part of the tab flow.

-->

<div class="focus-trap">
  <button data-tabindex="0">ZERO &times; escape</button>
  <button data-tabindex="2">two</button>
  <button data-tabindex="1">one</button>
  <button data-tabindex="3">three</button>
</div>

<div class="focus-trap cyclical">
  <button data-tabindex>four - B</button>
  <button data-tabindex>four - C</button>
  <button data-tabindex>four - A &times; escape</button>
</div>
<div>
  <button class="now-tabbable">seven</button>
  <div class="now-tabbable">five</div>
  <div class="now-tabbable">six</div>
</div>

Api用于控制带有DOM顺序的标签顺序。

然后,视觉顺序将需要与焦点顺序对齐。在示例代码中,您可以使用data-tabindex="i"来控制

聚焦陷阱可能是周期性的,必须明确地转义。

您可以调用该类并提供第二个参数true以建立包裹或循环顺序。

一种将非可列表元素放入制表符流的方法。

只有具有data-tabindex属性的元素才是可聚焦的。

没有正的tabIndex值。

你需要使用正data-tabindexes,但示例代码将始终只使用tabindex="0"使一个元素可聚焦。这意味着如果您通过制表符重新进入组,最后一个焦点元素将再次被聚焦。

© www.soinside.com 2019 - 2024. All rights reserved.