关于自定义模态对话框的可访问性问题
在浏览器中包含三个可直接用 JS 调用的对话框,这三个对话框分别是 alert
、prompt
、confirm
。这三个对话框无论是对于键盘还是屏幕阅读器的可访问性都支持的比较好。但是因为这三个对话框在不同浏览器下的效果都不一样,所以很少有网站会用这三个对话框,大多数网站都会使用自定义对话框。
但是国内大多数网站的自定义对话框可以说是没有做过任何可访问性方面的适配和优化,不仅屏幕阅读器无法朗读,就连键盘都无法正常访问。
下面是对话框可访问性的一些规范要求:
- 对话框内必须要有一个可聚焦的元素。
- 当对话框显示时,需要让对话框内的默认元素获取焦点。
- 关闭对话框后焦点需要回到打开对话框的元素上。
- 需要保证焦点始终在对话框内。
详细说明
对话框内必须要有一个可聚焦的元素
这里说的可聚焦的元素就是对话框内必须要有一个可获取焦点的元素,例如 button
之类的元素。
如果要使用 div
这一类不能获取焦点的元素来代替按钮的话请设置 tabindex
和 role
两个属性。
如果要使用字体图标的话,请设置 aria-label
属性。
让对话框内的默认元素获取焦点
打开对话框后需要让对话框内的可聚焦的默认元素获取焦点。这里的默认元素就是你希望用户点击的元素。如果对话框内同时包含按钮和输入框的话,可以让输入框获取焦点。
关闭对话框后焦点需要回到打开对话框的元素上
比如我点击 A按钮
打开了对话框,在我关闭对话框后焦点需要回到 A按钮
上。
需要保证焦点始终在对话框内
在网页中按 tab
键时,可聚焦的元素会按顺序获取焦点。在对话框内按 tab
键j焦点也会离开对话框。为了防止焦点离开对话框,在对话框内的最后一个可聚焦的元素按下 tab
键时,需要让对话框内的第一个可聚焦的元素获取焦点。
下面是 Google 云端硬盘的对话框:
可以看到光标始终在对话框内。
下面是百度网盘的对话框:
焦点可以切到对话框外操作其它功能。
对于使用键盘的盲人来说,保证焦点不离开对话框是很重要的,焦点一旦离开对话框,想再让焦点回到对话框就很难了。
示例
下面简单实现一个让键盘和屏幕阅读器都能正常访问的对话框:
HTML:
<!--显示对话框的链接-->
<ul>
<li><a href="javascript:;" class="show-dialog">打开对话框1</a></li>
<li><a href="javascript:;" class="show-dialog">打开对话框2</a></li>
<li><a href="javascript:;" class="show-dialog">打开对话框3</a></li>
<li><a href="javascript:;" class="show-dialog">打开对话框4</a></li>
</ul>
<!--对话框-->
<div
id="dialog"
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-content"
>
<p id="dialog-title">删除询问</p>
<p id="dialog-content">您确定要删除文件吗?</p>
<button class="confirm" type="button">删除</button>
<button class="cancel" type="button">取消</button>
</div>
上面的对话框比较简单。
对话框内的 role="dialog"
是告诉屏幕阅读器 这是一个 dialog
。
aria-modal="true"
是告诉屏幕阅读器这是一个模态对话框。
aria-labelledby="dialog-title"
是绑定对话框标题的 id
,当对话框内的元素获取焦点时,屏幕阅读器就会朗读对话框的标题。
aria-describedby="dialog-content"
是绑定对话框主要内容的 id
,当对话框内的第一个元素获取焦点时,屏幕阅读器就能朗读对话框的主要内容。
因为这里主要写的是可访问性优化,所以外观样式就写的比较简单了。
对话框效果如下:
对话框在默认情况下是隐藏的。
下面是 JS 代码:
var dialog = document.querySelector('#dialog'); // 对话框
var showDialog = document.querySelectorAll('.show-dialog'); // 打开对话框的链接
var cancel = document.querySelector('#dialog .cancel'); // 对话框内的取消按钮
var confirm = document.querySelector('#dialog .confirm'); // 对话框内的确认按钮
for (var i = 0; i < showDialog.length; i++) {
// 给打开对话框的链接添加点击事件
showDialog[i].onclick = function () {
dialog.style.display = 'block'; // 显示对话框
this.classList.add('active'); // 给被点击的元素添加一个 class
confirm.focus(); // 让对话框内的确认按钮获取焦点
};
}
// 对话框内的最后一个按钮键盘按下事件
cancel.onkeydown = function (ev) {
// 判断是否是 tab 键
if (ev.keyCode === 9) {
confirm.focus(); // 让确认按钮获取焦点
return false;
}
};
// 对话框内的取消按钮点击事件
cancel.onclick = function () {
dialog.style.display = 'none'; // 隐藏对话框
document.querySelector('.active').focus(); // 让打开对话框的元素获取焦点
document.querySelector('.active').classList.remove('active'); // 删除打开对话框的元素的 class
};
上面的 JS 代码只是简单演示,实际开发中 JS 代码可能会和上面的有些不一样。
最终效果如下:
对话框打开后 删除
按钮会获取焦点。
最后一个按钮按下 tab
键时,焦点又会回到第一个按钮上,只要对话框处于打开的状态,焦点就无法离开对话框。
对话框关闭后,焦点又会回到打开对话框的元素上。
相关文章:
版权声明:本文为原创文章,版权归 Mr. Ma's Blog 所有,转载请联系博主获得授权。
本文地址:https://www.misterma.com/archives/847/
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。