使 HTML 表单元素'display only' - 非交互式



我正在开发一个动态表单生成器,用户可以在其中向页面添加不同的内容块(按钮、文本输入、文本段落、图像等),稍后可以发布,这将是一个他们可以使用的简单HTML表单。

对于这个应用程序的"预览"部分(他们添加不同的内容块并修改内容和外观),我突然想到,最简单的方法是只显示最终产品HTML本身,这样我或多或少可以保证预览中显示的内容与实际形式中显示的相匹配。

这一点很重要,因为它有一些晦涩的风格怪癖,比如带有display:block的按钮的行为。

然而,我不希望预览像真正的形式那样是交互式的。也就是说,我不想要以下行为:

  • 输入接收焦点并能够插入内容
  • 具有点击动画的按钮
  • 单击链接导航
  • 出现默认悬停样式

此外,在可访问性方面,如果屏幕上出现一堆什么都不做的输入,可能会非常令人困惑。

有没有浏览器本机/标准的方法可以做到这一点?

我的后备方案可能是禁用所有元素。但例如,这对链接不起作用。

另一种选择可能是在表单顶部放置一个不可见的div,它可以捕获所有的点击事件。但我不喜欢无障碍POV。

是否使用role="presentation"

代码示例

作为此处的示例,请参阅此处的一些示例代码:https://codepen.io/dwjohnston/pen/qBrGPmr?editors=1111

现在,我有了带有role="button"的div-这些按钮是可点击的,-当你点击它们时,侧面板将显示内容配置,例如,输入的默认值、标签等。

已经出现了一个问题——交互式内容不允许出现在按钮内。

但同时,我不应该能够标记到这些控件,(现在我可以手动添加tabindex = "-1",但这不是完整的图片)。我不想混淆屏幕阅读器等

信息

对这个问题进行了编辑,解决了OP在当前实施中存在的具体问题。我把第一部分留在这里,作为我最初的答案。

我不希望预览像真正的形式那样是交互式的

为什么?让表单是交互式的对所有用户来说都是很好的(考虑到一些功能在预览中不需要完全工作)。

让人们看到默认的悬停样式是什么样子的,点击链接会做什么(即点击链接并提示"将导航到xxx页面")等等。

我理解我不想导航到新页面并提交表单(任何"保存"或"更新"操作加上任何"导航"操作),但我认为其他一切都应该能够在预览中工作。

此外,在可访问性方面,如果屏幕上出现了一堆什么都不做的输入,可能会非常令人困惑

如果屏幕上出现预览,但我无法导航到按钮、链接等,那将更加令人困惑。

对于屏幕阅读器用户来说,这会如何表现?即,你会使用aria-hidden="true"隐藏所有元素吗(在这种情况下,他们将如何测试页面?)。

我的后备方案可能是禁用所有元素。但例如,这对链接不起作用

这确实是最糟糕的处理方式之一,disabled输入通常无法接收焦点,因此键盘用户在测试时会受到影响。

此外,如果最终生产表单中的某些元素在填充某个字段之前被禁用(例如),那么用户如何在最终表单中测试它?

此外,如果你拦截了一个链接的导航,而没有解释为什么链接不起作用,也可能会造成混乱。(如果你向最终用户解释,这个链接会在"预览"模式下在新窗口中打开吗?显然,这取决于它是否是静态链接等,但只是考虑一下用户可以检查任何自定义链接指向正确位置的方式)。

建议的解决方案

我想说你需要两个版本的完成形式;真实世界";一和";预览";一

HTML可以是(读"应该是")相同的,但您需要实现JavaScript处理程序来禁用您不想激活的功能。

如果编辑工具只使用JavaScript是您关注的问题之一,那么它并没有错,只要您向最终用户提供该工具需要JavaScript才能工作的警告。(发布工具和最终用户体验的区别在于,您可以更加依赖JavaScript。)

例如:假设您有一个<button>,当单击它时,它应该向表单(在表单的生产版本中)添加新行,并且无论出于何种原因,您都不希望此功能在预览版本中处于活动状态。

在这种情况下,在表单的预览/演示版本中,当您点击该按钮时,可以显示CCD_;将向表单"添加新行;。

这样,屏幕阅读器用户和纯键盘用户就可以在不需要做太多额外工作的情况下测试表单(还可以查看表单在键盘用户使用时是否存在可用性问题!)

我认为这对每个人来说都是最清楚的,用户体验也会更好。

你只需要考虑在预览模式下导航(例如,关闭Esc)和快速编辑(当你预览表单时,如果表单特别长,可以选择聚焦之前聚焦的元素,只有键盘的用户会为此感谢你!当你回到编辑时,将焦点放回上次编辑的项目也是如此)。

进一步阅读

从可访问性的角度来看,在这种情况下,WCAG不是你想要的,创作工具可访问性指南(ATAG)是

这是一套鲜为人知的关于如何创建编辑器、所见即所得等的指南。

与所有W3C指南一样,这是一本很难阅读的书,但如果你理解核心原则,它将指导你做出好的决定,你可以在这里询问是否需要澄清一些不清楚的要点:-)。



编辑:如何使用当前设计实现可访问的界面

您链接的代码笔中的问题及其解决方案如下:

停止接收焦点的交互式项目

当你包装每个元素时,你已经正确地诊断出你最大的问题,那就是嵌套的交互式元素。

解决这个问题的方法很简单:如您所说,给每个交互元素一个tabindex="-1"。这样可以确保它们不会被错误地聚焦。

确保实际的包装项目可以集中并激活

然后,我们只需要确保包装器.content-item具有tabindex="0",以便将其添加到焦点顺序中。

我们还需要捕获EnterSpace键,并确保我们的面板也被它们激活。

视觉焦点指示器

我还向包装器添加了CCD_ 11;按钮";使得视觉聚焦指示器是可用的。

因此,这基本上解决了正常的键盘导航问题,下一个问题是屏幕阅读器如何解释嵌套的按钮、输入等。

屏幕阅读器校正

在这里,我也会简单地对屏幕阅读器完全隐藏按钮、输入等,并解释里面的元素。

实际上,我们使按钮不可见,而是描述.content-item的内容。

为了隐藏元素,我们使用aria-hidden="true"

为了宣布一些有意义的内容,我们可以在<span>中使用一些visually-hidden(仅限屏幕阅读器)文本。这将比在如此复杂的应用程序中使用CCD_ 16更健壮。

使用鼠标使应用程序运行良好

最后的挑战-停止鼠标事件。

幸运的是,pointer-events: none有很好的支持,即使在少数不支持它的浏览器上,点击输入也不是世界末日(我们已经为键盘用户修复了它)

解决所有问题的示例:

这解决了选择方法的所有问题。

请注意,它没有考虑组件本身的可访问性错误(例如,<input>没有<label>等),但我认为这只是因为它是一个例子。

唯一需要解决的是如何生成描述该项目的视觉隐藏文本和CCD_;按钮";行动

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>

您可能需要查看inert属性。目前任何浏览器都不支持它,但有polyfill库。

其想法是,在任何元素上标记这一点都将使其及其所有子元素不具有互动性,并且出于可访问性的目的而不可见。

你可以阅读一些背景知识并在这里下载库:

https://github.com/WICG/inert

试试这个

$(document).ready(function(){

var demoPage = $('div.demoPage');
demoPage.find('a').attr('href','#');
demoPage.find('button').attr("disabled", true)

})
div {
padding: 20px;
margin: 20px;
background: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="no-copy">
<p>You can't click me.</p>
</div> 
<div class="demoPage">

<a href="www.google.com" readonly="" class="no-copy">
It is a link

</a>

<button> It is a button</button>

</div>

<!--you can do this-->
<input type="text" id="input" disabled>
<script>
document.getElementById('input').disabled = true;
</script>

您可以通过添加一些css类来非常简单地做到这一点:

<div class="content-item disable-control" role="button" data-id="item-1">
<input type="text" />
</div>
<div class="content-item disable-control" role="button" data-id="item-2">
<button> I am a button</button>
</div>

^^我又加了一个";禁用控制";类

.content-item.disable-control * {
pointer-events: none;
cursor: inherit;
user-select: none;
}
.content-item.disable-control *::selection { 
background: transparent;
} 

如果需要,请确保添加一些浏览器指定的css,例如

*::-moz-selection

当然,你可以修改我的代码,只应用一次类(对于整个左窗格),而不是单独应用于每个控件

disabled属性添加到要禁用的所有表单元素中。

最新更新