1

WCAG 声明具有焦点的元素应该始终对用户可见。在空间有限的聊天窗口中,如果不是不可能的话,这尤其困难。

当键盘或屏幕阅读器用户选择第一个按钮选项并选择它时,内容会滚动并且按钮不再可见,从而打破了“焦点始终可见”的 WCAG 规则。此外,如果列表中有多个按钮,焦点将停留在按钮上,如果它们继续选项卡,窗口将滚动到设置焦点的位置。这是令人迷惑的,人们可以说,选择按钮时,其他选项无关紧要,因为现在可以使用新选项。

示例:https ://recordit.co/2jDDvqg98J

一种选择是在到达按钮时停止滚动以使按钮可见。但我觉得这不是很好的体验,也是遵守WCAG规则的妥协。我做了一些研究,所有对话式 UI 无一例外地在聊天中打印新内容时滚动到底部。如果我以上述方式偏离以保持在 WCAG 内,我将违反雅各布斯定律。

另一种选择是将焦点从所选按钮移到输入字段或下一个/新可用按钮列表中的第一个按钮。但我觉得这对于盲人用户来说会删除所有参考点。

您是否可以想到任何其他选项或设计来以可访问的方式解决此问题?

4

2 回答 2

0

不是完整的答案

这是一个太大的问题,无法完整回答,有数百件事情需要考虑,只有一个 GIF 才能看到我只能概括的行为。

离屏对焦

你已经把 WCAG 带到了绝对的字母上,而且有点过分了。这一点的目的是当我改变焦点时,焦点项目在屏幕上可见。

如果我滚动一个网页,你不能期望焦点项目留在页面上(否则,如果它比屏幕长度长,世界上没有任何页面是合规的!)。

只要当我关注下一个项目时,它就会滚动到视图中并有一个焦点指示器,我可以看到(正确的对比度,不依赖于颜色)你在这一点上被评为 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>

小提琴的解释

所以他们的关键点是在加载更多内容之前关注该 div 的 JavaScript 中视觉隐藏和伴随的行。 <div>

div 让我们在单击按钮后更改焦点。我还在该 div 内的文本中添加了“加载”以添加其他目的,因为您的应用程序将由 AJAX 驱动。

div 有tabindex="-1"所以它不能接收焦点。我还添加aria-hidden="true"了它,并在单击选项按钮时将其关闭,就在给它焦点之前。

当焦点在现实世界中离开这个 div 时,我会将它切换回来,但我并没有在快速演示小提琴中这样做。

这不是“失败”的WCAG吗?

是的!在此示例中,我将不可聚焦的项目设为可聚焦,但它没有任何操作。我仍然认为这比使它成为更好,<button>因为这意味着它有一个动作。显然并不完美。

然而,WCAG 的关键部分是“ G ”——它们是指导方针。我建议的方式是“hack”或妥协,因为我对开发时间和技术限制持现实态度。

您可以在没有 div 的情况下执行上述操作的“正确”方法是进行一些仔细的焦点管理。有了无限的时间和预算,我肯定会这样做。

但是考虑到您不必只考虑Tab屏幕阅读器的键(您可以通过链接、按钮、标题、部分等进行导航),这在尝试拦截击键时会变成一场噩梦,因此上述是最简单的方法我可以考虑这样做。

替代模式。

因为前面的例子'失败'WCAG 还有另一种选择,但是我认为这更糟并且引入了很多问题。

每次将 div 中的文本替换为新文本。

不利的一面是您每次都需要提供“上一个项目”按钮并跟踪它们,有利的一面是这将符合 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>

于 2020-05-09T09:12:28.170 回答
0

你的例子有点太复杂了。

让我们看一个标准的 HTML 页面:如果你用键盘聚焦一个元素,你仍然可以使用鼠标滚动页面(不修改键盘光标),并使元素从视口中消失。这不会使任何 WCAG 标准无效。

在 a 上按 char 键textarea将使其再次在视觉上集中。对于按钮或链接,则需要 tabthenshifttab使按钮可见并再次获得焦点。

视觉焦点和键盘焦点是两个不同的东西,但如果键盘焦点影响视觉焦点,那并没有相互影响

您可能遇到的问题不是焦点问题,而是时间限制问题。

  1. 如果用户不在窗口底部,则不要滚动,

  2. 如果在最后 N 秒内执行了某个操作,则不要滚动,如果在滚动之前没有执行其他操作,请等待 P 秒。

  3. 如果窗口不滚动,则表明已收到新消息。

如果您不在底部,我认为 Slack 可以很好地实现“不要滚动并指示新消息” 。

于 2020-05-09T14:57:44.813 回答