信息
对此问题进行了编辑,解决了 OP 在当前实施中遇到的具体问题。我将第一部分留在这里作为我的原始答案。
我不希望预览像真实表单那样真正具有交互性。
为什么?让表单具有交互性对所有用户来说都很棒(考虑到某些功能需要在预览中不能完全发挥作用)。
让人们看到默认的悬停样式是什么样的,点击链接会做什么(即点击链接并提示“将导航到 xxx 页面”)等等。
我了解我不想导航到新页面并提交表单(任何“保存”或“更新”操作以及任何“导航”操作),但我认为其他一切都应该能够在预览中工作。
此外,就可访问性而言,如果屏幕上出现一堆不执行任何操作的输入,可能会非常混乱。
如果屏幕上出现预览但我无法导航到按钮、链接等,那会更加混乱。
这对于屏幕阅读器用户会有什么表现?即,您是否会使用 aria-hidden="true" 隐藏所有元素(在这种情况下,他们将如何测试页面?)。
我的后备方案可能是禁用所有元素。但这不适用于例如链接。
这确实是您可以处理的最糟糕的方法之一,disabled 输入通常无法获得焦点,因此键盘用户在测试时会受到影响。
另外,如果最终生产表单中的某些元素在某个字段被填写之前被禁用(例如),那么用户如何在您的最终表单中测试呢?
此外,如果您拦截了链接的导航但没有解释链接为什么不起作用,这也可能导致混淆。 (如果您向最终用户解释,该链接是否可以在“预览”模式下在新窗口中打开?显然取决于它是否是静态链接等,但只是考虑用户可以检查任何自定义链接指向的方式正确的地方)。
建议的解决方案
我会说您需要两个版本的完成表格。 “真实世界”的一个和“预览”的一个。
HTML 可以(读作“应该”)相同,但您需要实现 JavaScript 处理程序以禁用您不想激活的功能。
让编辑工具仅在您担心的情况下使用 JavaScript 并没有错,只要您向最终用户发出警告,说明该工具需要 JavaScript 才能工作。 (发布工具和最终用户体验之间的区别在于您可以更加依赖 JavaScript。)
例如: 假设您有一个<button>,单击该<button> 应该在表单中添加一个新行(在表单的生产版本中),无论出于何种原因,您都不想要这个在预览版中启用的功能。
在这种情况下,在表单的预览/演示版本中,当您单击此按钮时,可能会显示alert,上面写着“将为表单添加新行”。
这样,屏幕阅读器用户和仅键盘用户就可以测试表单,而无需您做太多额外的工作(还可以查看表单在键盘用户使用时是否存在可用性问题!)
我认为这对每个人来说都是最清楚的,并且用户体验会更好。
您只需要考虑导航进出预览模式(例如,Esc 关闭)和快速编辑(当您预览表单时,如果表单特别长,只有键盘的用户会为此感谢您!当您返回编辑时,将焦点重新放在最后编辑的项目上)。
进一步阅读
从可访问性的角度来看,WCAG 不是您在这种情况下要寻找的,Authoring Tool Accessibility Guidelines (ATAG) 是。
这是一套鲜为人知的关于如何创建编辑器、所见即所得等的指南。
与所有 W3C 指南一样,这是一本繁重的读物,但如果您了解核心原则,它将指导您做出正确的决定,您可以随时在此处询问您是否需要澄清一些不清楚的个别要点:- )。
编辑:您如何使用当前设计实现可访问的界面
您在codepen you linked中遇到的问题及其解决方法如下:
停止接收焦点的交互项目
当您包装每个元素时,您已正确诊断出最大的问题,即嵌套交互元素。
解决方案非常简单:如您所说,给每个交互元素一个tabindex="-1"。这样可以确保它们不会被错误地聚焦。
确保实际的包装项目可以被聚焦和激活
然后我们只需要确保包装器.content-item 具有tabindex="0" 以便将其添加到焦点顺序中。
我们还需要捕获 Enter 和 Space 键,并确保我们的面板也被它们激活。
视觉焦点指示器
我还在包装“按钮”中添加了一个outline,以便可以使用视觉焦点指示器。
所以基本上解决了正常的键盘导航问题,下一个问题是屏幕阅读器将如何解释嵌套按钮、输入等。
屏幕阅读器更正
在这里我也很简单,从屏幕阅读器完全隐藏按钮、输入等,而是解释里面是什么元素。
实际上,我们使按钮不可见,而是描述.content-item 的内容。
为了隐藏我们使用aria-hidden="true"的元素
要宣布一些有意义的事情,我们可以在<span> 中使用一些visually-hidden (screen reader only) text。这将比在如此复杂的应用程序中使用aria-label 更加强大。
使用鼠标使应用程序表现良好
最终挑战 - 停止鼠标事件。
幸运的是pointer-events: none 有really good support,即使在少数不支持它的浏览器上能够点击输入也不是世界末日(我们已经为键盘用户修复了它)
已解决所有问题的示例:
这解决了您选择方法的所有问题。
请注意,它没有考虑组件本身的可访问性错误(例如 <input> 没有 <label> 等),但我认为这只是因为它是一个示例。
您唯一需要解决的是如何生成描述项目和.content-info“按钮”操作的视觉隐藏文本。
document.addEventListener("DOMContentLoaded", function () {
const items = document.getElementsByClassName("content-item");
const rightPanel = document.getElementById('right-panel');
for (let i = 0; i< items.length; i++) {
const item = items[i];
item.addEventListener("click", (e) => {
console.log(e.target);
const id = e.target.dataset.id;
rightPanel.innerHTML = id;
});
// ADDED this to capture the Enter and Space presses on our wrapper button
item.addEventListener("keydown", function(e){
if(e.keyCode == "32" || e.keyCode == "13"){
console.log(e.target);
const id = e.target.dataset.id;
rightPanel.innerHTML = id;
}
});
}
});
.main {
display: flex;
flex-flow: row nowrap;
}
.left {
flex: 1 1 auto;
}
.right {
flex: 1 1 auto;
}
.content-item {
margin-top: 20px;
width: 600;
border: solid 2px blue;
cursor: pointer;
}
/* ADDED a focus indicator so keyboard users know where they are */
.content-item:focus{
outline: 4px solid #333;
}
/* ADDED to stop pointer events reaching the input, button etc. */
input, button{
pointer-events: none;
}
/* ADDED the visually hidden class so we can provide meaningful text to screen reader users */
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<div class ="main">
<div class ="left">
<!-- Added `tabindex="0"` so the wrapper is focusable by keyboard -->
<div class="content-item" role="button" data-id="item-1" tabindex="0">
<!-- added `aria-hidden="true"` and `tabindex="-1"` to hide the input from screen readers and make sure it cannot be focused by keyboard, I also added `role="presentation"` just for good measure, although it shouldn't be needed. -->
<input type="text" aria-hidden="true" tabindex="-1" role="presentation">
<!-- Added this span that explains the action that the "content-item button" would perform if clicked. You need to come up with something meaningful for the contents of this -->
<span class="visually-hidden">Edit input [input identifier]</span>
</div>
<div class="content-item" role="button" data-id="item-2" tabindex="0">
<button aria-hidden="true" tabindex="-1" `role="presentation"`> I am a button</button>
<span class="visually-hidden">Edit button [button identifier]</span>
</div>
</div>
<div class ="right" >
<h2> Right panel</h2>
<div id ="right-panel">
</div>
</div>
</div>