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

问题描述 投票:38回答:5

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

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

为什么tabindex不能使标签集中注意力?

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

document.getElementById('checkbox').addEventListener('change', function (event) {
  document.getElementById('val').innerHTML = event.target.checked;
});
<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>

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

html5
5个回答
57
投票

为什么tabindex没有使标签可以集中?

简答:

  1. 标签是可聚焦的。
  2. TabIndex不会有任何区别。
  3. 欢迎来到浏览器/代理商不一致的世界。

tl;博士

label (Ref)元素非常集中。它的DOM接口是HTMLLabelElement,它源自HTMLElement (Ref),后者又实现了GlobalEventHandlers (Ref),因此暴露了focus()方法和onfocus事件处理程序。

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

这在HTML 4.01 Ref中提到:http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1

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

当LABEL元素获得焦点时,它会将焦点传递给其关联的控件。

此外,在其他地方(我无法掌握参考的那部分)我已经读到它取决于执行代理。 (不要相信我的话,我不太确定)。

然而,这意味着当你focus label(或label收到focus)时,focus被传递到其相关的可控制控件。这不会导致两个不同的focuses,但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. 点击“焦点标签”按钮
  2. 它应该聚焦标签,然后传递焦点并以蓝色突出显示其相关的复选框轮廓。
  3. Chrome-v39有效。 IE-v11它没有(不知何故html和正文确实响应:焦点)。 FF-v34有效。

谈论浏览器的不一致性,尝试使用“访问密钥”L。有些浏览器会关注复选框,而有些浏览器会点击它,即将操作传递给它。

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

这是一个片段:

label = $("label").first();
$("#btn").on("click", function() {
    label.focus();
});
* { margin: 8px; }
.highlight { background-color: yellow; }
:focus {
    outline: 2px solid blue;
}
<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" />

希望能消除你的疑虑。

.


你的问题:

现在focussing(原文如此)关于你无法聚焦标签的原始问题,因为你想通过在其位置放置图标类型的东西来不同地设置复选框的样式。

为了做到这一点,一个选择是你不要通过做display:none;完全隐藏它。相反,将其设为1x1像素并将其推到您的图标下方。这样它仍然可以自然地获得焦点,但却被有效地隐藏起来。

例如,如果您的图标是复选标记和十字形,则更改复选框的位置,并使标签上的::before::after伪元素中的图标。这将导致复选框仍然获得焦点,并使图标响应。这将使图标成为焦点的明显错觉。

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

片段:

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;
}
<input id="txt" type="text" value="input" /><br /><br />
<div class="chkGroup">
    <input id="chk" type="checkbox" />
    <label for="chk" accesskey="L">Checkbox</label>
</div>

.


3
投票

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

看看the full specification,你会看到有一种叫做tabindex focus flag的东西,它定义了tabindex属性是否真的会让这个字段“可以看到”。建议元素列表中缺少label元素。

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

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

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();
  }
});
.label,
.label:visited,
.label:hover,
.label:active {
  text-decoration: none;
  color: black;
}
<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>

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


0
投票

由于这篇旧帖子是html标签tabindex的顶级谷歌搜索结果之一,我想添加我非常简单的工作解决方案。正如@Abhitalks在接受的答案中提到的那样,标签的焦点被传递给它的相关控件。因此,要绕过此行为,只需在标签中添加tabindex并在event.preventDefault() focus中使用EventListener

@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],因为当我遇到这个问题时,这就是我正在做的事情。相同的原则适用于任何输入类型。


-3
投票

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

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

上面的Js甜蜜地做了这个伎俩。

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