为什么 tabindex 不能使标签成为焦点?
简答:
- 标签可聚焦。
- TabIndex 不会有任何区别。
- 欢迎来到浏览器/代理不一致的世界。
tl;dr;
label (Ref) 元素非常具有焦点。它的 DOM 接口是 HTMLLabelElement,它派生自 HTMLElement (Ref),后者又实现了 GlobalEventHandlers (Ref),因此公开了 focus() 方法和 onfocus 事件处理程序。
您无法获得labels 焦点行为的正确规范/参考文档的原因是因为您可能一直在查看 HTML5 规范。有趣的是,HTML5 refs 没有说明任何与此相关的内容,这增加了混乱。
这在 HTML 4.01 参考这里提到: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,而是input 上的一个focus(在您的情况下是一个复选框)。由于这种行为,tabindex 属性无法发挥作用。
这里还有 W3C 的网站可访问性 (WAAG) 测试套件:http://www.w3.org/WAI/UA/TS/html401/cp0102/0102-ONFOCUS-ONBLUR-LABEL.html,其中讨论了 onfocus 和 onblur 的实现 label。理想情况下,键盘或模拟键盘的辅助技术应该实现这一点。但是……
这就是浏览器不一致发挥作用的地方。
这个例子可以证明这一点。在不同的浏览器中检查以下sn -p。 (我已经针对 IE-11、GC-39 和 FF-34 对其进行了测试。它们的行为都不同。)
- 点击按钮“焦点标签”
- 它应该聚焦标签,然后传递焦点并将其关联的复选框轮廓突出显示为蓝色。
- Chrome-v39 有效。 IE-v11 它没有(不知何故 html 和 body 确实响应 :focus)。 FF-v34 有效。
谈到浏览器的不一致,请尝试使用“访问密钥”L。有些浏览器会关注复选框,而有些浏览器会点击它,即将动作传递给它。
这是一个 fiddle 来测试它:http://jsfiddle.net/abhitalks/ff0xds4z/2/
这是一个sn-p:
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 (sic) 解决您最初无法聚焦标签的问题,因为您想通过在其位置放置一个图标类型的东西来以不同的方式设置复选框的样式。
为了做到这一点,您可以选择不通过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>
.