文章大纲与涵盖范围
继上篇介绍完无障碍网站(Web Accessibility,又称为 a11y)的目的与实践方向,中、下篇将着重在 React Advanced Guide 里提供的 Accessibility 指南。
在可以广泛运用的 Accessibility 实作知识上,hightlight React 对此的支援(例如 JSX 是否也能直接应用某些 HTML 属性?)或者调整(某些属性在 React 里,可能有写法的差异)。
下篇会使用一个案例,介绍滑鼠点击事件的实作,并且使用 React 生态系中的测试工具测试效果。
实作 Mouse and pointer events 的 Accessibility 优化
请想像一个需求:在画面上,有三个按钮,第一个按钮点击之後,会 pop up 出一个子目录列表,这个列表需要可以关掉,第二三个按钮点击之後,会跳出 alert 视窗(但在这个案例我们不用关注二跟三)。
你会怎麽设计这个元件呢?以下是一个很直观,但其实对於键盘使用者不太友善的做法,你是否也看出端倪了呢?原本的 React 文件使用 class component,这里我用 hook 稍加改写。
首先,让我们把元件上的按钮先画出来,并且设定好列表 pop up 的状态,再加上点击按钮之後会展开列表的函式。
export const ClickExample = () => {
const [isShowOption, setIsShowOption] = useState(false)
const onClickHandler = () => {
setIsShowOption(true)
}
return (
<>
<div>
<button onClick={onClickHandler}>Select an option</button>
{isShowOption && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
<button>Another button</button>
<button>The other button</button>
</>
)
}
加入了一些排版之後,此时的画面看起来:
接下来,我们要加入一个点击空白处,就可以把列表关起来的方法。在这里新增了一个 ref ,并指向底下的子目录列表外层元素,让我们可以获得 current 的状态。当点击范围不在列表元素的 current 范围里的时候,就收合列表。
export const ClickExample = () => {
//..
const toggleContainer = useRef(null);
useEffect(() => {
const onClickOutsideHandler = (event) => {
if (isShowOption && !toggleContainer.current.contains(event.target)) {
setIsShowOption(false);
}
}
window.addEventListener('click', onClickOutsideHandler);
return () => {
window.removeEventListener('click', onClickOutsideHandler);
};
});
return (
<Container>
<div ref={toggleContainer}>
//..
)}
此时的画面看起来:
用滑鼠控制的情况下,还算顺利。然而当使用者用键盘时,就会遇到问题。(以下的画面键盘顺序为:使用 tab 切换到第一个按钮,按下 enter 打开子目录,接下来按 enter 或是 tab 都无法把子目录关上)。
此时,可以利用别的 event handlers 事件来改善这个情境,拿掉点击空白处关闭列表的设定。可以设计成侦测使用者的滑鼠、Focus 的状态,如果已经离开了按钮一一段时间,就自动关上列表。如此一来,不管是键盘或是滑鼠的使用者,可以顺畅的操作画面。
所以在这里把原本的 ref 以及 event listener 拿掉,侦测按钮,当别的按钮被 focus 而按钮一的 focus 状态解除时,就把子目录列表关上。这里使用 setTimeout 的原因是:blur event 会比新的 focus event 更早触发,而我们必须要先去确认别的按钮是否被 focus 才能决定是否要关上列表。
export const ClickExample = () => {
//..
let timeOut
const onBlurHandler = () => {
timeOut = setTimeout(() => {
setIsShowOption(false);
})
}
const onFocusHandler = () => {
clearTimeout(timeOut);
}
return (
// React assists us by bubbling the blur and focus events to the parent.
<Container>
<div onBlur={onBlurHandler} onFocus={onFocusHandler}>
//..
)
}
经过调整之後,画面的互动看起来像是这样:
使用滑鼠
使用键盘
JSX 的无障碍网页 Development Tools
Crete React App 会自动装载 eslint-plugin-jsx-a11y 这个套件(所以 Create Next App 也是有的)。
如果你想要引入更多的 accessibility 规则提示,可以调整你的 .eslintrc
档案。你可以到这里 https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules 来看看它支援的规则。
加上去之後,就可以看到相关提示了!例如下图是在说 <img>
元素必须有个 alt 属性来说明内容。
这一张则是跟表单有关的设定。
关於这些规则,套件里的文件也都写得相当清楚。
如果觉得要改善自己的专案 Accessibility 毫无头绪,不妨安装这个套件开始,从提示反查去了解各项规范。
>>: Ruby on Rails CRUD 之 U(Update)
接下来的文章,我把范围限缩在「桌上型作业系统」,目前主流的作业系统有 Windows, macOS,...
Medium 的特色 Medium 基本上是为了部落格而生的平台,简约的排版画面、所见即所得的编辑器...
继续昨天~ 拉取三个Label,这是往後会从资料库回传资料到我们在主画面拉的tableview里显示...
嘛,铁人赛来到第 28 天,同时也宣告我的铁人赛库存没有了(剩下一篇写到一半的库存是 for 第 3...
後来发现 , 之前说明了 Vue . React Component 如何变成 Web Compon...