Tabindex 在 Chrome 中不起作用(React 应用程序)
Tabindex not working in Chrome (React app)
我使用 react 和 react-modal 在网站上创建覆盖。该叠加层包含各种元素以及一个表单(下面的概述)。我希望能够使用 TAB 键引导用户浏览表单。我将 tabindex=0
分配给了按出现顺序可标记的所需元素。
我的问题是:它在 Chrome(版本 61.0.3163.100)中不起作用,而在 Firefox 中却可以。我读到,如果 DOM-树上的任何元素不可见或 height/width 为 0,就会发生这种情况。我进行了一些样式更改以修复该问题,但没有效果。
<div class="ReactModalPortal">
<div data-reactroot="" class="ReactModal__Overlay" style="position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px;">
<div class="ReactModal__Content" tabindex="-1" aria-label="Questionnaire" style="position: absolute; top: 0px; left: 0px; right: 0px; height: 100%; background: transparent none repeat scroll 0% 0%; overflow: auto;">
<!-- Some other stuff and nested elements -->
<div id="...">
<form>
<input tabindex="0">
<button tabindex="0">
</form>
</div>
</div>
</div>
如您所见,其中一个父元素具有 tabindex="-1"
。当通过 Chrome 中的检查功能或以编程方式使用 JS 更改它时,问题仍然存在(或者如果元素最初是使用此索引呈现的,是否有所不同?)。
更新
我意识到是其他原因导致了问题。我在模态的根节点上使用 CSS 属性 initial: all
来将我的内部 CSS 与外部的所有内容隔离开来。由于某种原因,这阻止了 tabindex 工作。如果你能帮助我理解,我会奖励这个赏金。我的解决方法就是不使用 all: initial
(它无论如何都不兼容 IE,但我也没有真正好的替代方法)。
all: initial
重置具有初始属性的节点的所有 CSS 属性。
对于display
属性,初始值为inline
。
因此,将 all: initial
设置为根 div 会将 display
属性 设置为内联。 inline
元素没有高度或宽度,因此它们是 0x0。
这也是因为 div
只包含固定的、绝对定位的元素。
React Modal 通过 运行 遍历模态内所有元素的循环检查元素是否可聚焦。但是,对于可聚焦的元素,它必须是可见的。对于每个元素,我们必须迭代直到 body 元素以确保它的可见性。
这是检查元素是否可见的函数。
function hidden(el) {
return (
(el.offsetWidth <= 0 && el.offsetHeight <= 0) || el.style.display === "none"
);
}
如您所见,我们的 div 将没有 offsetHeight
或 offsetWidth
,因此将被视为隐藏。因此,模态不能不被聚焦。
我遇到了同样的问题,无法让其他解决方案快速运行,所以我想出了蛮力方法。对容器元素进行引用,该容器元素包含您希望使其成为可选项卡的可聚焦元素。
const formRef = useRef();
<ReactModalTabbing containerRef={formRef}>
<form ref={formRef} onSubmit={handleSubmit} >
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
</form>
</ReactModalTabbing>
这是组件
import React, { useState, useEffect } from 'react';
const ReactModalTabbing = ({ containerRef, children }) => {
const [configuredTabIndexes, setConfiguredTabIndexes] = useState(false);
const focusableElements = () => {
// found this method body here.
//https://zellwk.com/blog/keyboard-focusable-elements/
return [...containerRef?.current?.querySelectorAll(
'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"]):not([type="hidden"]):not([disabled])'
)];
}
const isTabbable = (element) =>{
if(element.getAttribute('tabindex')){
return true;
}
return false;
}
const findElementByTabIndex = (tabIndex) => {
return containerRef?.current?.querySelector(`[tabindex="${tabIndex}"]`);
}
const moveFocusToTabIndex = (tabIndex) => {
findElementByTabIndex(tabIndex)?.focus();
}
const handleKeyDownEvent = (event) => {
if(!isTabbable(event.target)){
return;
}
const tabIndex = parseInt(event.target.getAttribute('tabindex'));
if(event.shiftKey && event.key === 'Tab'){
moveFocusToTabIndex(tabIndex - 1);
}else if(event.key === 'Tab'){ //should probably make sure there is no other modifier key pressed.
moveFocusToTabIndex(tabIndex + 1);
}
}
useEffect(() => {
if(!configuredTabIndexes && containerRef.current){
setConfiguredTabIndexes(true);
focusableElements().forEach((el, index) => el.setAttribute('tabindex', index + 1));
containerRef?.current?.addEventListener('keydown', handleKeyDownEvent);
}
});
return children;
}
export default ReactModalTabbing;
我使用 react 和 react-modal 在网站上创建覆盖。该叠加层包含各种元素以及一个表单(下面的概述)。我希望能够使用 TAB 键引导用户浏览表单。我将 tabindex=0
分配给了按出现顺序可标记的所需元素。
我的问题是:它在 Chrome(版本 61.0.3163.100)中不起作用,而在 Firefox 中却可以。我读到,如果 DOM-树上的任何元素不可见或 height/width 为 0,就会发生这种情况。我进行了一些样式更改以修复该问题,但没有效果。
<div class="ReactModalPortal">
<div data-reactroot="" class="ReactModal__Overlay" style="position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px;">
<div class="ReactModal__Content" tabindex="-1" aria-label="Questionnaire" style="position: absolute; top: 0px; left: 0px; right: 0px; height: 100%; background: transparent none repeat scroll 0% 0%; overflow: auto;">
<!-- Some other stuff and nested elements -->
<div id="...">
<form>
<input tabindex="0">
<button tabindex="0">
</form>
</div>
</div>
</div>
如您所见,其中一个父元素具有 tabindex="-1"
。当通过 Chrome 中的检查功能或以编程方式使用 JS 更改它时,问题仍然存在(或者如果元素最初是使用此索引呈现的,是否有所不同?)。
更新
我意识到是其他原因导致了问题。我在模态的根节点上使用 CSS 属性 initial: all
来将我的内部 CSS 与外部的所有内容隔离开来。由于某种原因,这阻止了 tabindex 工作。如果你能帮助我理解,我会奖励这个赏金。我的解决方法就是不使用 all: initial
(它无论如何都不兼容 IE,但我也没有真正好的替代方法)。
all: initial
重置具有初始属性的节点的所有 CSS 属性。
对于display
属性,初始值为inline
。
因此,将 all: initial
设置为根 div 会将 display
属性 设置为内联。 inline
元素没有高度或宽度,因此它们是 0x0。
这也是因为 div
只包含固定的、绝对定位的元素。
React Modal 通过 运行 遍历模态内所有元素的循环检查元素是否可聚焦。但是,对于可聚焦的元素,它必须是可见的。对于每个元素,我们必须迭代直到 body 元素以确保它的可见性。
这是检查元素是否可见的函数。
function hidden(el) {
return (
(el.offsetWidth <= 0 && el.offsetHeight <= 0) || el.style.display === "none"
);
}
如您所见,我们的 div 将没有 offsetHeight
或 offsetWidth
,因此将被视为隐藏。因此,模态不能不被聚焦。
我遇到了同样的问题,无法让其他解决方案快速运行,所以我想出了蛮力方法。对容器元素进行引用,该容器元素包含您希望使其成为可选项卡的可聚焦元素。
const formRef = useRef();
<ReactModalTabbing containerRef={formRef}>
<form ref={formRef} onSubmit={handleSubmit} >
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
</form>
</ReactModalTabbing>
这是组件
import React, { useState, useEffect } from 'react';
const ReactModalTabbing = ({ containerRef, children }) => {
const [configuredTabIndexes, setConfiguredTabIndexes] = useState(false);
const focusableElements = () => {
// found this method body here.
//https://zellwk.com/blog/keyboard-focusable-elements/
return [...containerRef?.current?.querySelectorAll(
'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"]):not([type="hidden"]):not([disabled])'
)];
}
const isTabbable = (element) =>{
if(element.getAttribute('tabindex')){
return true;
}
return false;
}
const findElementByTabIndex = (tabIndex) => {
return containerRef?.current?.querySelector(`[tabindex="${tabIndex}"]`);
}
const moveFocusToTabIndex = (tabIndex) => {
findElementByTabIndex(tabIndex)?.focus();
}
const handleKeyDownEvent = (event) => {
if(!isTabbable(event.target)){
return;
}
const tabIndex = parseInt(event.target.getAttribute('tabindex'));
if(event.shiftKey && event.key === 'Tab'){
moveFocusToTabIndex(tabIndex - 1);
}else if(event.key === 'Tab'){ //should probably make sure there is no other modifier key pressed.
moveFocusToTabIndex(tabIndex + 1);
}
}
useEffect(() => {
if(!configuredTabIndexes && containerRef.current){
setConfiguredTabIndexes(true);
focusableElements().forEach((el, index) => el.setAttribute('tabindex', index + 1));
containerRef?.current?.addEventListener('keydown', handleKeyDownEvent);
}
});
return children;
}
export default ReactModalTabbing;