WCAG指出具有焦点的元素应始终对用户可见。在空间有限的聊天窗口中,即使不是没有可能,这也特别困难。
[当键盘或屏幕阅读器用户使用Tab键选择第一个按钮选项时,内容滚动且按钮不再可见,从而打破了“始终可见焦点” WCAG规则。同样,如果列表中有多个按钮,则焦点将停留在该按钮上,并且如果它们继续进行制表,则窗口将滚动到设置焦点的位置。这令人迷惑,并且可以争辩说,选择按钮时其他选项不相关,因为现在可以使用新选项。
示例:https://recordit.co/2jDDvqg98J
一种选择是在到达按钮时停止滚动,以使按钮可见。但是我觉得这不是很好的经验,也不是遵守WCAG规则的妥协。我进行了一些研究,所有对话UI均无一例外地在聊天中打印新内容时滚动到底部。如果我以上述方式偏离以保持在WCAG之内,那么我将破坏Jakobs Law.
另一个选项是将焦点从所选按钮移至输入字段或下一个/新的可用按钮列表中的第一个按钮。但是我认为这将为盲人用户消除所有参考点。
您是否可以想到其他任何选项或设计来解决此问题?
这是一个太大的问题,无法完全回答,有数百个问题需要考虑,只有一个GIF才能看到我只能概括的行为。
您已将WCAG带到绝对字母,但距离太远了。这一点的目的是,当我change聚焦时,聚焦的项目在屏幕上可见。
如果滚动网页,您将无法期望焦点的项目停留在该页面上(否则,如果世界上的任何页面都超过屏幕长度,则该页面将不符合要求!]
只要我关注下一个项目,它就会滚动到视图中并且具有焦点指示器,我可以看到(正确的对比度,而不取决于颜色),您在这一点上的等级为WCAG AAA!
这是事情变得“模糊”的地方。在您的示例中,内容已添加到聊天框中,因此当前关注的项目从屏幕上滚动出来。
现在,如果我们将焦点移到最新选项(出现的按钮),我们会遇到一个问题,即它可能会中断屏幕阅读器的运行,因此他们无法听到所有先前的信息,因此必须返回并再次收听。
[如果我们不移动焦点,则您遇到的问题是您在我按Tab时所描述的(例如),并且页面跳回到了我刚才收听的内容之前。
假设我们没有其他选择,这仍然是更好的选择(不是集中精力,但是我们确实有选择。)>
这是可访问性的乐趣所在,由于这里没有确定的模式,我们需要找到一些解决方法。
我会争辩说,这里最大的问题是一旦说出新文本,当我们按下Tab
或其他焦点快捷键时,我们会跳回到页面顶部。一个解决方法是创建一个特殊的div,第二个我选择一个选项时将其聚焦。
此div应该有tabindex="-1"
,所以不能通过键盘访问(只能通过编程方式访问。)>
第二个我选择一个选项,我们将重点放在此div上,然后开始插入文本。
这样,当我按下<kbd>Tab</kbd>
或下一个按钮的快捷方式时,它将跳到第一个新选项。
我在下面创建了一个基本的小提琴,它需要进行一些改进,但是为您提供了一种测试/使用的模式。
var hasLoadedMore = 0; $('.loadMore').on('click', function(e){ if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option. console.log("option chosen"); $('#focusAdjuster').attr('aria-hidden', false); $('#focusAdjuster').focus(); console.log("focus adjusted"); loadContent(); } }); function loadContent(){ ///ugly way of simulating the content being added dynamically. $('#chat').append('<p>additional text</p>'); $('#chat').append('<p>more text</p>'); setTimeout(function(){ $('#chat').append('<p>more text</p>'); $('#chat').append('<button>Option 1 new</button>'); $('#chat').append('<button>Option 2 new</button>'); }, 500); hasLoadedMore = 1; }
.visually-hidden { position: absolute !important; height: 1px; width: 1px; overflow: hidden; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); white-space: nowrap; /* added line */ }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="chat"> <p>initial text</p> <button class="loadMore">Option 1</button> <button class="loadMore">Option 2</button> <button class="loadMore">Option 3</button> <div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div> </div>
因此,它们的关键点是visually-hidden <div>
以及JavaScript中用于突出显示div的伴随行之前
div让我们在单击按钮后更改焦点。我还向该div中的文本添加了“加载”功能,以增加其他用途,因为您的应用程序将使用AJAX技术。
div具有tabindex="-1"
,因此无法获得焦点。我还添加了aria-hidden="true"
并在单击选项按钮时将其切换为关闭状态,就在将其聚焦之前。
当焦点离开现实世界中的这个div时,我会切换回去,但我并没有在快速的演示小提琴中这样做。
这不是“失败”的WCAG吗?是的!在此示例中,我使不可聚焦的项目可聚焦,并且没有任何动作。我仍然认为这比将其设置为<button>
更可取,因为这意味着它可以执行操作。显然这并不完美。
但是WCAG的关键部分是'G
'-它们是G准则。基于我对开发时间和技术局限性的看法,我建议的方式是“ hack”或妥协。您可以在没有div的情况下完成上述操作的“正确”方法是进行一些仔细的焦点管理。有了无限的时间和预算,我一定会做到的。
但是考虑到您不必只用屏幕阅读器来考虑Tab
键(您可以通过链接,按钮,标题,部分等进行导航),当尝试截取按键和因此,以上是我可以想到的最简单的方法。因为前面的示例“失败”了WCAG,所以还有另一种选择,但是我认为这更糟,并引入了许多问题。
每次用新文本替换div中的文本。
缺点是您每次都需要提供'previous item'按钮并进行跟踪,其好处是这符合WCAG(尽管我认为即使您'通过'该标准也不太实用)。
还提供那些“上一个”按钮再次在焦点管理中引入了许多问题(当我们使它们可见时,它们是否获得焦点,它们是否会增加混乱?)。>
像表单向导模式那样思考,每组问题都是一个“步骤”,因此您可以返回上一步,并且只能在屏幕上看到当前步骤。
我加入了此模式,因为可以通过一些思考来扩展此模式,并向OP /其他人提供一些想法,请不要按原样使用它]]] >> var hasLoadedMore = 0;
var optionChosen = "";
$('.loadMore').on('click', function(e){
if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
optionChosen = $(this).text();
console.log("option chosen", optionChosen);
loadContent();
}
});
function loadContent(){
$('#chat').html('<button class="previousQuestion">You chose ' + optionChosen + '<span class="visually-hidden">(click here to go back and chose a different option)</span></button>');
$('#chat').append('<h3>' + optionChosen + '</h3>');
///ugly way of simulating the content being added dynamically.
$('#chat').append('<p>additional text</p>');
$('#chat').append('<p>more text</p>');
setTimeout(function(){
$('#chat').append('<p>more text</p>');
$('#chat').append('<button>Option 1 new</button>');
$('#chat').append('<button>Option 2 new</button>');
}, 500);
hasLoadedMore = 1;
$('.previousQuestion').on('click', function(){
console.log("now you would restore the previous question");
});
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>