tabIndex不会使用Tab键使标签可聚焦

时间:2014-12-18 15:44:28

标签: html5

我试图用图标替换复选框/无线电输入。为此,我需要隐藏原始复选框/收音机。问题是,我还希望表单正确支持键盘输入,即让输入通过Tab键保持可聚焦,并使用Spacebar进行选择。由于我隐藏了输入,因此无法对其进行聚焦,因此我尝试使其<label>可以聚焦。

This documentation以及其他各种来源让我相信我可以使用tabindex属性(对应HTMLElement.tabIndex属性)来做到这一点。但是,当我尝试将tabindex分配给我的标签时,它仍然像往常一样没有重点,无论我多少尝试Tab

为什么tabindex无法使标签具有焦点?

以下代码段演示了此问题。如果您使用鼠标聚焦输入并尝试使用Tab聚焦标签,则它不起作用(它会将以下<span>tabindex重点关注)。

&#13;
&#13;
document.getElementById('checkbox').addEventListener('change', function (event) {
  document.getElementById('val').innerHTML = event.target.checked;
});
&#13;
<div>
  <input type="text" value="input">
</div>
<div>
  <label tabindex="0">
    <input type="checkbox" id="checkbox" style="display:none;">
    checkbox: <span id="val">false</span>
  </label>
</div>
<span tabindex="0">span with tabindex</span>
&#13;
&#13;
&#13;

(JavaScript代码只允许看到正确点击标签(联合国)检查复选框。)

5 个答案:

答案 0 :(得分:55)

  

为什么没有tabindex使标签可以聚焦?

简答

  1. 标签是可聚焦的。
  2. TabIndex没有任何区别。
  3. 欢迎来到浏览器/代理商不一致的世界。
  4. <强> TL;博士;

    label (Ref)元素非常易于关注。它的DOM接口是HTMLLabelElement,它派生自HTMLElement (Ref),后者又实现了GlobalEventHandlers (Ref),从而暴露了focus()方法和{{1}事件处理程序。

    您无法获得onfocus焦点行为的正确规范/参考文档的原因是因为您可能一直在查看HTML5规范。有趣的是,HTML5引用并未说明与此相关的任何内容,这增加了混淆。

    HTML 4.01参考文献中提到了这一点:http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1

    特别是在第17.9.1节末尾和17.10之前:

      

    当LABEL元素获得焦点时,它会将焦点传递给它   相关控制。

    另外,在其他地方(我无法掌握ref 的那一部分)我已经读过它取决于执行代理。 (不要接受我的话,我不太确定)。

    但是,这意味着当您label focus(或label收到label)时,focus会被传递给focus其相关的可控制控件。这不会导致两个不同的focus es,而focus上的一个input(在您的情况下是一个复选框)。由于此行为,tabindex属性无法发挥作用。

    W3C还提供了一个关于网站可访问性(WAAG)的测试套件:http://www.w3.org/WAI/UA/TS/html401/cp0102/0102-ONFOCUS-ONBLUR-LABEL.html,其中讨论了onfocusonblurlabel的实施。理想情况下,键盘或模拟键盘的辅助技术应该实现这一点。但是......

    这是浏览器不一致的地方。

    这可以通过这个例子来证明。在不同的浏览器中查看以下代码段。 (我已经针对IE-11,GC-39和FF-34进行了测试。所有这些都表现不同。)

    1. 点击按钮&#34; 焦点标签&#34;
    2. 它应该聚焦标签,然后传递焦点并以蓝色突出显示其相关的复选框轮廓。
    3. Chrome-v39有效。 IE-v11它没有(不知何故html和正文确实响应:焦点)。 FF-v34有效。
    4. 说到浏览器不一致,请尝试使用&#34;访问密钥&#34; 。有些浏览器会关注复选框,而有些浏览器会点击它,即将操作传递给它。

      这是一个小提琴来测试它:http://jsfiddle.net/abhitalks/ff0xds4z/2/

      以下是代码段

      &#13;
      &#13;
      label = $("label").first();
      $("#btn").on("click", function() {
          label.focus();
      });
      &#13;
      * { margin: 8px; }
      .highlight { background-color: yellow; }
      :focus {
          outline: 2px solid blue;
      }
      &#13;
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <input id="txt" type="text" value="input" /><br />
      <label for="chk" accesskey="L">Checkbox: </label>
      <input id="chk" type="checkbox" /><br />
      <input id="btn" type="button" value="Focus Label" />
      &#13;
      &#13;
      &#13;

      希望能够解除你的疑虑。


      您的问题:

      现在focus唱歌( sic )关于你无法对标签进行聚焦的原始问题,因为你想通过在其中放置一个图标类型的东西来不同地设置一个复选框的样式的地方。

      为了做到这一点,您可以选择 通过执行display:none;完全隐藏它。相反,将其设为1x1像素并将其推到您的图标下方。通过这种方式,它仍然可以自然地获得焦点并且有效地隐藏。

      例如,如果您的图标是复选标记交叉,则更改复选框的位置,并使图标超出::before或{ {1}}标签上的伪元素。这将导致复选框仍然获得焦点,并使图标响应。这将使图标成为焦点的明显错觉。

      演示小提琴:http://jsfiddle.net/abhitalks/v0vxcw77/

      <强>

      &#13;
      &#13;
      ::after
      &#13;
      div.chkGroup { position: relative; }
      input#chk {
          position: absolute;
          width: 1px; height: 1px;
          margin: 0; margin-top: 4px; outline: none;
          border: 1px solid transparent; background-color: transparent;
      }
      label::before {
          content: '\2714';
          position: relative;
          width: 18px; height: 18px;
          background-color: #fff;
          margin-right: 8px; padding: 2px;
          display: inline-block; 
          border: 1px solid transparent;
      }
      input#chk:checked + label::before {
          content: '\2716';
      }
      input#chk:focus + label::before {
          border: 1px solid #00f;
      }
      &#13;
      &#13;
      &#13;

答案 1 :(得分:3)

编辑:以下是对规范的误读:

  

the full specification,   你会看到有一种名为tabindex focus flag的东西,   它定义tabindex属性是否实际生成该字段   &#34; tabbable&#34 ;.建议列表中缺少label元素   元素。

     

但是再一次,span元素也是如此,所以请看图:)。

那就是说,y 你可以通过将整个事物包装在另一个元素中,或者使用一些JavaScript来强制解决问题,使标签文本可聚焦。不幸的是,包装(这里是一个锚点)可以让人们在CSS和JS中有相当多的额外工作来使其像普通的label元素一样工作。

&#13;
&#13;
document.getElementById('checkbox').addEventListener('change', function(event) {
  document.getElementById('val').innerHTML = event.target.checked;
});
document.getElementsByClassName('label')[0].addEventListener('click', function(event) {
  event.target.getElementsByTagName('label')[0].click();
  event.preventDefault();
});
document.getElementsByClassName('label')[0].addEventListener('keypress', function(event) {
  if ((event.key || event.which || event.keyCode) === 32) {
    event.target.getElementsByTagName('label')[0].click();
    event.preventDefault();
  }
});
&#13;
.label,
.label:visited,
.label:hover,
.label:active {
  text-decoration: none;
  color: black;
}
&#13;
<div>
  <input type="text" value="input">
</div>
<div>
  <a class="label" href="#">
    <label tabindex="0">
      <input type="checkbox" id="checkbox" style="display:none;">checkbox: <span id="val">false</span>
    </label>
  </a>
</div>
<span tabindex="0">span with tabindex</span>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

正如之前的海报所说: 标签焦点始终直接转到输入元素。

如果某人有一些花哨的(但是假的)复选框隐藏了原来的复选框,并且无法看到键盘导航的实际焦点,那会非常烦人。

我能想到的最佳解决方案:javascript。

将实际焦点放在一边,取而代之的是假的:

    input[type=checkbox]:focus {
        outline: none;
    }
    .pseudo-focus {
        outline: 2px solid blue;
    }

并注意(在许多情况下明显隐藏)原始复选框的更改:

    $('input[type=checkbox')
        .focus( function() {
            $(this).closest('label').addClass('pseudo-focus');
        })
        .blur( function() {
            $(this).closest('label').removeClass('pseudo-focus');    
        });

完整jsfiddle here

答案 3 :(得分:0)

由于此旧帖子是 html标签tabindex 的Google最佳搜索结果之一,所以我想添加一个非常简单的工作解决方案。正如@Abhitalks在接受的答案中提到的那样,标签的焦点传递给了它的关联控件。因此,要绕过此行为,只需在标签上添加tabindex,然后在focus EventListener中使用event.preventDefault()

@Heretic Monkey的回答中有一个正确的主意,但您不需要包装元素即可实现此目的。但是,您将需要手动转发所有必需的击键(如空格键)。

例如:

'use strict';

let field = document.getElementById('hidden-file-chooser');
let label = document.querySelector('label[for=hidden-file-chooser]');

// prevent focus passing
label.addEventListener('focus', event => {
  event.preventDefault();
});

// activate using spacebar
label.addEventListener('keyup', event => {
  if (event.keyCode == 32) {
    field.click();
  }
});
#hidden-file-chooser {
  display: none;
}

input[type=text] {
  display: block;
  width: 20rem;
  padding: 0.5rem;
}

label[for=hidden-file-chooser] {
  display: inline-block;
  background: deepskyblue;
  margin: 1rem;
  padding: 0.5rem 1rem;
  border: 0;
  border-radius: 0.2rem;
  box-shadow: 0 0 0.5rem 0 rgba(0,0,0,0.7);
  cursor: pointer;
}
<input type="text" placeholder="Click here and start tabbing through ...">

<input id="hidden-file-chooser" type="file">
<label for="hidden-file-chooser" tabindex="0"> Select a File </label>

<input type="text" placeholder="... then shift+tab to go back.">

P.S:在示例中,我使用了input[type=file],因为这是我遇到此问题时要进行的工作。相同的原理适用于任何输入类型。

答案 4 :(得分:-2)

对于输入类型的收音机或复选框:

opacity: 0;
height: 0;
width: 0;
min-height: 0;
line-height: 0;
margin: 0;
padding: 0;
border: 0 none;

上面的Js很甜蜜。