如何允许屏幕阅读器在错误地将焦点移动到字段时宣布 ASP.NET MVC 5 表单验证消息?
How to allow screen readers to announce ASP.NET MVC 5 form validation messages when moving focus to the field in error?
我们有一个 ASP.NET MVC 5 网络应用程序。我们使用 JAWS 结合 Internet Explorer 11(企业授权)和 Chrome 定期进行可访问性测试。当用户 TAB 进入字段时,我们将 运行 解决 JAWS 未读取与表单字段关联的验证消息的问题。我们使用 FluentValidation 和标准 HTML 助手来显示表单字段和验证消息(下面的示例):
@Html.LabelFor(model => model.Email)
@Html.EditorFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email, null, new { role = "alert" })
示例 FluentValidation 可能会在数据库中查询表单中的电子邮件地址,并显示 "This e-mail has already been taken" 在服务器端运行的消息。
发送回浏览器的结果HTML是:
<label for="Email">E-mail address:</label>
<input type="text" name="Email" id="Email" ...>
<span class="..." data-valmsg-for="Email" data-valmsg-replace="true" role="alert">
This e-mail has already been taken
</span>
没有任何内容将验证消息与表单字段相关联。我一直认为 MVC 框架会自动建立这个连接,但显然它不会。
根据 WebAIM,我们应该利用 aria-describedby
属性将表单字段与内联验证错误相关联,但是重新部署现有的 MVC5 框架来做到这一点是一项艰巨的任务。
如何在不重写主要 HTML 帮助程序的情况下让屏幕阅读器在将焦点置于由 ASP.NET MVC5 生成的表单字段时宣布内联验证消息?
从纯粹的 html 角度来看,aria-describedby
属性就是您处理该问题的方式。
<label for="Email">E-mail address:</label>
<input type="text" id="Email" aria-describedby="more_stuff">
<span id="more_stuff">
This e-mail has already been taken
</span>
我不确定为什么这需要 "replumbing" 框架或编写 "major" 助手,但我不是 asp.net 用户。如果框架不允许您将描述与字段相关联,则说明框架存在缺陷,应向框架提交功能请求。
如果不创建自定义 HtmlHelper
扩展方法来在 for 控件中生成 aria-describedby
属性,并在错误元素中生成关联的 id
属性,您将需要使用 javascript 添加它们。
请注意,每个错误消息占位符(由 @Html.ValidationMessageFor()
生成)都通过 data-valmsg-for="...."
属性与其表单控件相关联。
假设您想要为所有表单控件包含 aria-describedby
以及关联的错误消息(并且在 <form>
元素中),以便在通过 [= 添加客户端错误时它可用18=],那么脚本 (jQuery
) 将是
$(function () {
// Get the form controls
var controls = $('form').find('input, textarea, select')
.not(':hidden, :input[type=submit], :input[type=button], :input[type=reset]');
$.each(controls, function (index, item) {
// Get the name of the form control
var name = $(this).attr('name');
if (!name) {
return true;
}
// Get the associated error element
var errorElement = $('[data-valmsg-for="' + name + '"]');
if (!errorElement) {
return true;
}
// Generate an id attribute based on the name of the control
var errorId = name + "-error"
// Add attributes to the input and the error element
$(this).attr('aria-describedby', errorId)
errorElement.attr('id', errorId);
});
});
如果您对客户端验证错误不感兴趣,那么您可以使用 var controls = $('.input-validation-error');
作为选择器来仅获取添加了服务器端验证错误的表单控件。
我建议将此脚本包含在外部(例如)screenreadervalidation.js
文件中,并将其包含在您的 jquery
或 jqueryval
包中,以便它包含在包含表单的所有视图中用于创建或编辑数据。
我通过 data-val-*
属性使用不显眼的验证,并创建包含验证错误消息的跨度,以便我可以控制放置。这样一来,我还可以轻松地为他们分配一个 ID 并使用 aria-describedby
。当发生错误并在客户关注输入时填充 span 时,reader 会找到相关的 span ID 并读取出现在那里的错误。这里的关键部分是 aria-describedby="NameOfCustomerError"
匹配 id="NameOfCustomerError"
将出现错误的位置(因为它是带有 data-valmsg-for="NameOfCustomer"
的元素,表示它会自动显示该输入的错误)。
<input data-val="true"
data-val-required="@($"{CustomerResource.Label_Name}: {SharedResource.Validation_General}")"
data-val-minlength-min="4"
data-val-minlength="@CustomerResource.Validation_NameOfCustomer"
type="text" maxlength="100"
name="NameOfCustomer" id="NameOfCustomer"
class="form-control" aria-describedby="NameOfCustomerError"
placeholder="@CustomerResource.Label_Name" />
<span role="alert" id="NameOfCustomerError" class="field-validation-valid text-danger" data-valmsg-for="NameOfCustomer" data-valmsg-replace="true"></span>
我们有一个 ASP.NET MVC 5 网络应用程序。我们使用 JAWS 结合 Internet Explorer 11(企业授权)和 Chrome 定期进行可访问性测试。当用户 TAB 进入字段时,我们将 运行 解决 JAWS 未读取与表单字段关联的验证消息的问题。我们使用 FluentValidation 和标准 HTML 助手来显示表单字段和验证消息(下面的示例):
@Html.LabelFor(model => model.Email)
@Html.EditorFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email, null, new { role = "alert" })
示例 FluentValidation 可能会在数据库中查询表单中的电子邮件地址,并显示 "This e-mail has already been taken" 在服务器端运行的消息。
发送回浏览器的结果HTML是:
<label for="Email">E-mail address:</label>
<input type="text" name="Email" id="Email" ...>
<span class="..." data-valmsg-for="Email" data-valmsg-replace="true" role="alert">
This e-mail has already been taken
</span>
没有任何内容将验证消息与表单字段相关联。我一直认为 MVC 框架会自动建立这个连接,但显然它不会。
根据 WebAIM,我们应该利用 aria-describedby
属性将表单字段与内联验证错误相关联,但是重新部署现有的 MVC5 框架来做到这一点是一项艰巨的任务。
如何在不重写主要 HTML 帮助程序的情况下让屏幕阅读器在将焦点置于由 ASP.NET MVC5 生成的表单字段时宣布内联验证消息?
从纯粹的 html 角度来看,aria-describedby
属性就是您处理该问题的方式。
<label for="Email">E-mail address:</label>
<input type="text" id="Email" aria-describedby="more_stuff">
<span id="more_stuff">
This e-mail has already been taken
</span>
我不确定为什么这需要 "replumbing" 框架或编写 "major" 助手,但我不是 asp.net 用户。如果框架不允许您将描述与字段相关联,则说明框架存在缺陷,应向框架提交功能请求。
如果不创建自定义 HtmlHelper
扩展方法来在 for 控件中生成 aria-describedby
属性,并在错误元素中生成关联的 id
属性,您将需要使用 javascript 添加它们。
请注意,每个错误消息占位符(由 @Html.ValidationMessageFor()
生成)都通过 data-valmsg-for="...."
属性与其表单控件相关联。
假设您想要为所有表单控件包含 aria-describedby
以及关联的错误消息(并且在 <form>
元素中),以便在通过 [= 添加客户端错误时它可用18=],那么脚本 (jQuery
) 将是
$(function () {
// Get the form controls
var controls = $('form').find('input, textarea, select')
.not(':hidden, :input[type=submit], :input[type=button], :input[type=reset]');
$.each(controls, function (index, item) {
// Get the name of the form control
var name = $(this).attr('name');
if (!name) {
return true;
}
// Get the associated error element
var errorElement = $('[data-valmsg-for="' + name + '"]');
if (!errorElement) {
return true;
}
// Generate an id attribute based on the name of the control
var errorId = name + "-error"
// Add attributes to the input and the error element
$(this).attr('aria-describedby', errorId)
errorElement.attr('id', errorId);
});
});
如果您对客户端验证错误不感兴趣,那么您可以使用 var controls = $('.input-validation-error');
作为选择器来仅获取添加了服务器端验证错误的表单控件。
我建议将此脚本包含在外部(例如)screenreadervalidation.js
文件中,并将其包含在您的 jquery
或 jqueryval
包中,以便它包含在包含表单的所有视图中用于创建或编辑数据。
我通过 data-val-*
属性使用不显眼的验证,并创建包含验证错误消息的跨度,以便我可以控制放置。这样一来,我还可以轻松地为他们分配一个 ID 并使用 aria-describedby
。当发生错误并在客户关注输入时填充 span 时,reader 会找到相关的 span ID 并读取出现在那里的错误。这里的关键部分是 aria-describedby="NameOfCustomerError"
匹配 id="NameOfCustomerError"
将出现错误的位置(因为它是带有 data-valmsg-for="NameOfCustomer"
的元素,表示它会自动显示该输入的错误)。
<input data-val="true"
data-val-required="@($"{CustomerResource.Label_Name}: {SharedResource.Validation_General}")"
data-val-minlength-min="4"
data-val-minlength="@CustomerResource.Validation_NameOfCustomer"
type="text" maxlength="100"
name="NameOfCustomer" id="NameOfCustomer"
class="form-control" aria-describedby="NameOfCustomerError"
placeholder="@CustomerResource.Label_Name" />
<span role="alert" id="NameOfCustomerError" class="field-validation-valid text-danger" data-valmsg-for="NameOfCustomer" data-valmsg-replace="true"></span>