javascript 鼠标
在我的上一篇关于SitePoint的文章中 ,我质疑屏幕阅读器是否可以使AJAX脚本技术可用,并发现在大多数情况下它们不能。 这样做令人失望-指出一个问题而无法提供任何答案。 但是我真的别无选择,因为据我所知,没有任何具体的解决方案可提供。 (尽管自那时以来,其他开发人员进一步扩大了界限 ;特别重要的是Gez Lemon和Steve Faulkner在这一领域所做的工作 。)
但是可访问性并不总是那么困难! 我对此感到非常敏感,因为很多人将其视为一大堆问题,而实际上可访问性只是另一个设计挑战,通常,它比其他任何问题都没有困难或问题。 AJAX是一个特别尴尬的示例。 但是,在大多数情况下,提供可访问性确实并不难。
您不能总是得到想要的东西。
但是如果您有时尝试,您可能会发现,您会得到所需的东西。
—滚石
在本文中,我想对那些尝试使其Web应用程序可访问的用户表示满意。 为了实现这一点,在介绍与设备无关的脚本时,我将讨论一些与JavaScript可访问性相关的更基本的可解决问题。
键盘导航?
我们大多数人在大多数图形界面导航中都使用鼠标,但是有些人不能,因此必须使用键盘来导航。 例如,对于患有手部震颤的人来说,有效地使用鼠标所需的精确控制可能根本就不可能。 对于屏幕阅读器等辅助技术的用户,键盘是主要的交互方法。 毕竟,在看不见指针的情况下使用鼠标相当困难!
提供键盘访问权限还可以提供更好的可用性,因为尽管如此,许多可以使用鼠标的人还是喜欢在某些任务或特定时间使用键盘。 这些人通常是高级用户-通常更熟悉其计算机工作原理的人员,并期望能够根据需要使用鼠标或键盘与功能进行交互。
如果您不习惯使用键盘浏览网站,请立即尝试! 花一些时间在自己的网站上以及经常访问的其他网站上,以感受一下不用鼠标冲浪的感觉。 发现出现问题的地方,并考虑如何避免这些问题。
设备独立!
提到“键盘”访问总是有点误导,因为它本身不仅仅是我们在谈论的键盘。 我们正在谈论尝试提供设备独立性,以便无论用户的交互方式如何,他们都可以使用脚本。
例如,鼠标事件可能根本不会由鼠标生成。 它们可能是由轨迹球或手持游戏机上的模拟棒的移动引起的。 焦点事件可能是由键盘用户使用Tab键导航或由Opera用户使用浏览器的语音控制功能说出的导航命令产生的。
从理论上讲,我们希望能够支持任何交互方式,无论输入设备是什么。 但是实际上,所有这些形式的交互通常可以归结为两种基本类型之一:“鼠标”(单击或移动界面元素)和“键盘”(通过字符输入提供输入或指令)。 这些处理浏览器公开的事件的两个相当谨慎的子集,而忽略了大多数编程事件(加载,错误等)。
三大Struts
我假设您已经非常熟悉鼠标事件的脚本编写,而仅查看键盘事件的脚本编写。 (如果您需要事件的介绍,以及对现代JavaScript技术在现实世界中使用情况的详细介绍,您可能希望阅读我的书 。)为此,我要讨论三件事:三件事您可能会说“Struts”,它们共同为设备独立性奠定了基础:
- 提供可访问的交互式元素。
-
- 选择适当的触发元素。
-
- 旨在配对脚本挂钩,而不是事件挂钩。 这些术语现在可能没有意义,但是到您阅读完本文时,这些术语才有意义。
我也希望您牢记,当我们经历这些问题时,迎合可及性就是要提供等同性,这与等同性不同。 我们是否为不同的用户提供不同的路径并不一定重要,只要每个人都有一条通往同等最终结果的路径即可。
稍后,当我们看一些实际的示例时,我们将看到什至根本不同的方法如何整体上也可以导致等效的结果。
提供可访问的交互式元素
首先,如果要捕获来自键盘的输入,则需要使用可以接受焦点的元素:主要是链接( <a> )和表单控件( <input> , <select> , <textarea>和<button> )。 请注意,也可以将焦点分配给图像映射中的<area>元素, <frame>或<iframe> ,在某些情况下还可以将<object> (取决于其嵌入的数据类型),并且在大多数情况下浏览器,文档或documentElement本身。
对于这些交互,我们只能处理的事件是键盘实际上可以生成的事件:主要是focus , blur (当当前聚焦的元素失去焦点时触发), click (通过键盘激活链接或按钮在编程上与单击相同)。 (使用鼠标),以及三个按键操作事件: keydown , keyup和keypress 。
除了这些直接输入事件外,我们还可以使用编程事件-即响应状态变化而间接触发的事件。 编程事件的示例包括臭名昭著的window.onload事件和XMLHttpRequest对象的onreadystatechange事件。
我们还可以使用与模式无关的事件,即,用户的交互模式对其触发方式或触发时间没有任何影响的事件,例如表单的提交事件。
但是,这是一个重要的警告,这并不意味着我们不必将特定于鼠标的事件分配给废纸,,也不必将无法聚焦的元素放到一边。 这只是意味着我们将不得不重新考虑我们处理某些任务的方法。 请记住,这是关于等价而不是平等。 只要每个用户都可以访问其中至少一个,所有路径都是好的。
选择适当的触发元素
我使用术语“触发元素”来指代用于触发行为响应的任何元素。 触发元素是用户与之交互以便引起其他事情发生的东西。 这可能是指向flickr上的照片“添加标签”的简单链接:

或者它可以在照片的顶部包含一系列图标,旨在允许用户执行诸如将照片添加到自己的收藏夹中的操作:

但是,正如我们已经指出的,实现这些触发器可用的元素的选择是有限的。
现在, <button>元素是我的特别喜欢的元素,因为它非常灵活:它可以像其他任何元素一样设置样式,可以包含其他HTML,可以启用或禁用,并将状态报告给用户代理,并且它可以用作活动触发元素而没有任何值。 但是,像所有<form>元素一样,其唯一有效的上下文在<form>内部。
相比之下,使用链接作为触发器的问题在于,尽管可以使它们以任何喜欢的方式出现,但它们始终必须具有某种值:键盘上的href属性中没有任何内容的链接是不可访问的。
通常公认的最佳实践是使用渐进增强功能 -包括指向等效的非脚本功能的默认href属性-但这在我们完全脚本化的环境中工作(例如,处理链接)时不一定适当它本身是在满足其他地方非脚本用户的应用程序中通过脚本生成的。 这种情况通常导致需要链接具有“ # ”或“ javascript:void(null) ”或类似的(本质上是垃圾) href 。
但是,所有这一切都与要点无关,因为我们对元素的选择应基于触发器的实际作用和作用。 为了方便起见,我们不能只使用<button>来避免链接问题,反之亦然。 我们必须考虑语义,并尝试确保触发元素看起来像是触发元素,并且其外观与其功能一致。
这并不总是那么容易。 flickr图标示例是一个特别棘手的示例。 让我们再来看一遍:

这些图标的整体外观表明它们是按钮,例如Photoshop或MS Office中的工具栏按钮。 但是从功能上讲,前三个是脚本操作,而最后一个实际上是指向另一个页面的链接。
因此,前三个应该是<button>元素,而最后一个是<a>吗? 也许“所有尺寸”应该是一个单独的链接,而该链接根本不属于此工具栏?
那么“添加标签”链接呢?

那不是一个按钮,而是一个按钮,因为它是脚本操作,而不是页面视图? (而且,当我们在使用它时,如果JavaScript不可用,它是否不应该做某些事情……?)
在这种情况下,总的结论可能是flickr的界面设计与Web 2.0的大部分形式一样,只是一种偶然性,并且没有经过适当的考虑。
但是,所有这一切确实很重要-语义不只是注视肚脐的一种练习。 元素的选择对用户代理非常重要,因为它们依赖于标记语义来识别内容是什么,而这又对希望有效使用该内容的普通用户而言至关重要。
如果您仍然觉得这仅仅是关于语义纯净的学术讨论,那么让我们看一个实际的示例,说明在现实世界中触发元素选择为何重要的原因:Opera的键盘导航。
Opera在导航表单元素时使用的键与在链接中导航时使用的键不同(表单元素使用Tab键,而链接导航分别对“下一个”和“上一个锚点”使用“ A”和“ Q”)。 因此,如果我们使用看起来像链接按钮的界面元素,反之亦然,则将为使用键盘导航的Opera用户创建一个认知和可用性问题。
再举一个例子,让我们检查一下Basecamp在其Writeboard应用程序中的作用:

“编辑此页面”看起来就像一个按钮,因此我们应该能够像其他按钮一样使用Tab键; 但是我们不能,因为它根本不是按钮。 这是一个样式链接。
毕竟它应该是一个<button> ,因为这就是它的样子。 还是应该只是(看起来像)一个简单的链接,因为它实际上所做的是加载整个新页面? 在这种情况下,我认为是后者。
就像我说的那样,这方面并不总是那么容易,但是如果应用程序要像使用键盘一样直观,就必须考虑它。 通常,我认为应该将链接用于加载新页面而不发布任何数据(即GET请求)的操作,并且应将按钮或其他适当的表单小部件用于其他所有操作。 (毕竟,除了复杂形式之外,什么是应用程序?)。 HTTP 1.1规范回应了该视图,该规范指出GET请求不应用于将更改资源的操作,例如删除,创建或更新内容。
但是在所有情况下,触发器元素必须看起来像它的样子。
寻找行为配对,而不是事件配对
用于WCAG 1.0的HTML技术建议,一种满足设备独立性的好方法是提供冗余的输入事件-同一元素“配对”在一起的两个处理程序。 它提供的示例包括将keydown与mousedown配对,或使用keyup与mouseup搭配使用。
但是,这是解决提供设备独立性问题的错误方法,因为键盘和鼠标事件在概念上是不同的,并且在许多情况下,行为完全不同。 在我们的实际示例的第一部分中,我们将很快看到这种差异。
我认为从行为配对而非事件配对的角度进行思考会更有帮助。 如果您有某个功能是由mousedown事件驱动的,请不要认为“我如何使用keydown事件来使这项工作正常进行?” 只是想一想:“我如何才能通过键盘进行这项工作?”
我会劈头发吗? 我不这么认为。 当以这种方式考虑时,问题会导致不同的答案。 第一个问题询问一种特定的方法,该方法可能有效也可能无效。 第二个问题只是询问是否有方法; 它对任何兼容的解决方案都是开放的。 在我们的最后一个实际示例中,“拖放”将使我们看到思维上的巨大差异。
一些实际的例子
让我们看一些实际的例子。 我不会在这里深入研究代码。 这只是对鼠标实现的一些不同类型脚本的基本回顾; 我们还将考虑如何在键盘上实现它们。
简单的滚动和显示内容
一个简单的过渡效果可能包括链接上的颜色或背景图像更改。 您可能比不熟悉应用了块显示的链接以及:hover和:focus伪类,以便它们可以进行后台交换而无需JavaScript。
只要使用适当的链接或其他可聚焦的元素(不只是纯文本内容元素,如<span>或<td> ),脚本化的过渡通常就很容易扩展到键盘。 在我们的第一个示例中,我们将通过切换类名(例如,使用假设的addEvent函数)来触发单个元素的简单效果;当您在自己的工作中应用代码时,可以用它代替 —您可以选择自己喜欢的):
addEvent(link, 'mouseover', function()
{
link.className = 'rollover';
});
addEvent(link, 'mouseout', function()
{
link.className = '';
});
我们可以简单地添加一对focus和blur处理程序,以对通过键盘导航的人们执行相同的工作:
addEvent(link, 'focus', function()
{
link.className = 'rollover';
});
addEvent(link, 'blur', function()
{
link.className = '';
});
当处理一组元素上的事件时,情况会更加复杂,因为焦点事件不会冒泡。 当一个元素传递触发其父元素的事件时,就会发生事件冒泡。 尽管我们可以使用单个文档级侦听器(有时称为事件委托 )来处理任何元素上的鼠标事件,但对于不会冒泡的事件,我们不能做同样的事情:
addEvent(document, 'mouseover', function(e)
{
var target = typeof e.target != 'undefined'
? e.target : e.srcElement;
//"target" is whatever node the event bubbles up from
});
这种方法之所以有效,是因为鼠标事件从发生时起就冒泡了。 但是,由于焦点事件不会冒泡,因此此类函数将仅处理文档节点上发生的事件。
如果要捕获一组元素中每个元素上的事件,则必须遍历这些元素并将侦听器分别绑定到每个元素:
var links = list.getElementsByTagName('a');
for(var i=0; i<links.length; i++)
{
addEvent(links[i], 'focus', function()
{
//and so on ...
});
}
请记住,鼠标到键盘行为的确切转换不一定是正确的,因为这两种行为之间的可用性问题通常非常不同。 考虑DHTML菜单中的打开和关闭计时器。 这些对于鼠标是必需的,但对于键盘则是不希望的。 毕竟,用户使用键盘导航时不可能“滑出菜单”边缘,因此所有计时器都提供了无用的菜单暂停功能。
AJAX和其他RPC脚本
AJAX脚本编写的核心处理程序性事件,例如XMLHttpRequest对象的onreadystatechange事件或用于数据检索的iframe的load事件。 用户的交互方式不会影响这些事件的行为,因此我们不需要特别考虑每种交互方式。
但是,我们确实有两个要考虑的重点。
首先,最明显的是,我们应该首先考虑如何触发这些过程。 如果要通过用户操作启动请求或过程,则必须确保该操作可以由键盘用户触发。 正如我们已经讨论过的,该解决方案仅是选择合适的触发元素的问题。
第二个问题要求仔细构造响应HTML,以确保我们维持可用的制表符顺序。 如果我们响应用户操作而创建新内容,并且该新内容本身是交互式的,则必须确保将其插入HTML中的逻辑点。
例如,假设我们有一个“用户首选项”表单,用户可以在其中指定其个人详细信息。 在这种情况下,他们必须提供原籍国信息:
<label for="country" id="country-selector">
<span>Country: </span>
<select id="country">
<option value=""></option>
<option value="uk">UK</option>
<option value="au">Australia</option>
</select>
</label>
<input type="button" value="Save details" id="save-button" />
我们可以将onchange事件侦听器附加到select元素,该事件侦听器运行代码以创建辅助选择,允许用户选择合适的县或州。 但是,我们希望键盘用户可以立即访问辅助选择,因此我们应该将其插入正确的位置-在第一个标签之后,按钮之前:
var button = document.getElementById('save-button');
button.parentNode.insertBefore(newselect, button);
本示例假定已经创建了新的选择器和标签,并将其保存到对象引用newselect中。
拖放
无论您是否要使其可访问,“拖放”功能在最佳情况下都需要复杂的脚本编写! 乍一看,使此功能可访问的任务看起来是不可能的,因为拖动'n'的动作是mousemove事件,没有键盘等效项。 但是只要稍加思考,就可以做到!
想象一下,我们的应用程序包含一个垂直列表或一列框,用户可以拖动'n'下拉框来重新排序。 用户的鼠标拾取一个对象,将其移动,然后将其捕捉到新位置; 动作的最终结果只是对象顺序的改变-用户拖动的对象已经向上或向下移动了x个空格。 我们不能使用向上和向下箭头键生成的命令来达到相同的结果吗?
确实,我们可以,但是要做到这一点,我们需要键盘的触发元素:可聚焦的元素(可拖动对象本身或其中的某些东西),可以处理来自箭头键的事件。
在下图中,您可以看到一个指示鼠标行为的框。 顶部的较暗带是鼠标的触发元素。 用户单击该区域并移动鼠标以拖动该框。 因此,此行为的主要活动事件是mousemove :

现在,如果我们在可拖动元素内添加链接或按钮,并将其设置为看起来像图形图标的样式,则可以将该图标用作键盘的触发元素。 在这种推理方式下,该行为的主要活动事件是keypress :

从这个例子中,我们可以看到事件配对是徒劳的。 mousemove和keypress事件之间的功能相似性很小,但这是我们需要为鼠标和键盘用户提供的两个事件。 为了使此功能适用于键盘,我们逐步完成了概念上的旅程,从而展示了我们如何实现最终目标-等效功能。 实现的细节就是细节。
这些图片来自实际的脚本,该脚本太大了,无法在此处复制,但是如果您想下载并使用它,可以在我的网站上找到它。
可访问性不是功能
在我的想象中,没有并发症。
- 凯莉·米洛
可访问性设计就像盖房子的基础—从一开始就很容易,但是之后很难破解。
显然,最好的方法是从项目一开始就考虑可访问性-认识到可访问性是设计考虑因素,而不是功能。 确实, 乔·克拉克(Joe Clark)对Basecamp的可访问性的评估指出,如果将可访问性视为一项功能,则可能会忽略它。 “大多数开发人员无论如何都会忽略它;大多数开发人员都不知道关于可访问性的第一件事,甚至不知道它的重要性。” 可以肯定的是,这是令人怀疑的,但这是事实。
牢记这一点,在此我想给您举例说明一些很酷和鼓舞人心的东西,这些确实确实体现了该领域的最佳实践。 它不是新的(它已经存在了一年多,它是由Derek Featherstone在Web Essentials 2005上开发和提出的),但是其纯粹的优雅和简单性仍然让我大吃一惊: 它是语义,可访问的填字游戏 。
我们不可能像德里克一样有才华! 但是,从日常实践的角度来看,我希望我已经开始证明与设备无关的脚本确实不是那么困难或复杂。 这可能与我们过去的工作方式有所不同,但真正需要做的只是一点点额外的思考。
翻译自: https://www.sitepoint.com/accessible-javascript/
javascript 鼠标