我正在开发一个非常旧的网站,尝试更新它以便屏幕阅读器用户可以访问。特别是,我试图找出编码一些单选按钮的最佳方法,其中是/否值有条件地显示其他表单字段。
我有一个原型:https://jsfiddle.net/vpyx47qr/
注意:这只是一个原型,尽管 html 是松散 围绕我正在更新的真实表单构建的。
选中“是”单选按钮时,应显示一些额外字段。选中“否”时,不会显示这些字段。如果您单击原型中的无线电,您就会看到我正在尝试做什么。
“是”单选按钮上有
aria-expanded="false"
和 aria-controls="SpouseYesFields"
属性。
相应的“是”表单字段位于
<div id="SpouseYesFields" role="region" aria-labelledby="SpouseYes" class="spouse-fields" hidden>
$(function() {
var $radios = $('[name=spouse]');
$radios.click(function() {
if (this.value === 'true') {
$('#SpouseYes').attr('aria-expanded', true);
$('#SpouseYesFields').attr('hidden', false);
} else {
$('#SpouseYes').attr('aria-expanded', false);
$('#SpouseYesFields').attr('hidden', true);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<fieldset>
<legend>step 5</legend>
<p>Are you applying with your spouse?</p>
<ol role="radiogroup" aria-required="true">
<li>
<label for="SpouseYes">
<input id="SpouseYes"
name="spouse"
type="radio"
value="true"
aria-describedby="error-subscriber-applying-with-spouse"
aria-expanded="false"
aria-controls="SpouseYesFields">
Yes
</label>
</li>
<li>
<label for="SpouseNo">
<input id="SpouseNo" name="spouse" type="radio" value="false" aria-describedby="error-subscriber-applying-with-spouse">
No
</label>
</li>
<div id="error-subscriber-applying-with-spouse" class="intake-error-message" hidden>
Please select one.
</div>
<!--spouse progressive disclosure-->
<div id="SpouseYesFields" role="region" aria-labelledby="SpouseYes" class="spouse-fields" hidden>
<li>
<label for="label1">some label</label>
<input id="label1" type="text">
</li>
<li>
<label for="label2">some label2</label>
<input id="label2" type="text">
</li>
<li>
<label for="label3">some label3</label>
<input id="label3" type="text">
</li>
</div>
</ol>
</fieldset>
</form>
该网站已经使用 jquery,我将继续使用它来更新此表单。
我所做的就是切换单选按钮的 aria-expanded 属性
aria-expanded="true|false"
并在那些额外的“yes”字段周围的包装 div 上添加或删除 hidden
属性。如果您检查原型中的这些元素,然后在“是”/“否”之间单击,您将看到这一点。
这是以可访问的方式提供这种渐进式披露功能的最佳方式还是有更好的方式?
GOV.UK 设计系统团队不久前发布了有关有条件揭示问题的可访问性的更新。
在其无线电组件页面上,他们提供了一些更新的指南,用于有条件地揭示相关问题
保持简单。如果相关问题很复杂或有多个部分,请在流程的下一页上显示。
您可能会考虑将表单分成几页,具体取决于您的用例。
其组件也值得注意的是,显示的字段直接位于显示它们的单选按钮之后,这使得关系更加清晰。
GOV.UK 正在跟踪无线电组件问题的进一步研究
aria-expanded
实际上并不是为radio
设计的,所以也会缺乏支持。所以一切都取决于布局和结构。
<fieldset>
如果您决定将所有内容保留在同一页面上,则可能应该使用
group
而不是 region
,甚至更好,使用 <fieldset>
对相关输入进行分组。
region
是一个 landmark
角色,“非常重要 [...] 将其列在页面摘要中”。这似乎有些夸张,尤其是在它是条件内容块的前提下。
如果您在切换后立即显示这些输入,则
role=radiogroup
也不相关。您还应该用 <fieldset>
替换整体分组。
必须管理
radiogroup
中的焦点,如果依赖字段属于同一分组,则您需要按Tab来聚焦它们。
A
radiogroup
、group
和 form
必须具有可访问的名称,但您的示例中缺少该名称。
在表单模式下使用屏幕阅读器时,用户通过 Tab 直接跳转到单选按钮。前面的文本只有在分配给分组角色时才会被读取。
<p id="radio-question">Are you applying with your spouse?</p>
<ol role="group" aria-labelledby="radio-question">
一般来说,您应该避免绑定到像
click
这样的用户事件,而倾向于使用像 change
这样的 DOM 事件。这使您的代码对于副作用(例如其他脚本更改值)更加稳健。
如果使用库没有真正的优势,那么你应该始终求助于普通 JavaScript。
因为这样做只会强化对库的依赖。切换到另一个库总是会变得更加困难,在某些时候无缘无故地强制完全重写。
const radios = document.querySelectorAll('[name=spouse]'),
spouseYes = document.getElementById('SpouseYes'),
spouseYesFields = document.getElementById('SpouseYesFields');
radios.forEach(r => r.addEventListener('change', function() {
const target = event.target;
if (target.value === 'true') {
target.setAttribute('aria-expanded', true);
spouseYesFields.hidden = false;
} else {
spouseYes.setAttribute('aria-expanded', false);
spouseYesFields.hidden = true;
}
}));
<form aria-labelledby="form-title">
<h2 id="form-title">Something form</h2>
<fieldset>
<legend>Step 5</legend>
<p id="radio-question">Are you applying with your spouse?</p>
<ol role="group" aria-labelledby="radio-question">
<li>
<label for="SpouseYes">
<input id="SpouseYes"
name="spouse"
type="radio"
value="true"
aria-expanded="false"
aria-controls="SpouseYesFields">
Yes
</label>
</li>
<!--spouse progressive disclosure-->
<fieldset id="SpouseYesFields" hidden>
<legend>Information about your spouse</legend>
<li>
<label for="label1">some label</label>
<input id="label1" type="text">
</li>
<li>
<label for="label2">some label2</label>
<input id="label2" type="text">
</li>
<li>
<label for="label3">some label3</label>
<input id="label3" type="text">
</li>
</fieldset>
<li>
<label for="SpouseNo">
<input id="SpouseNo" name="spouse" type="radio" value="false">
No
</label>
</li>
</ol>
</fieldset>
</form>
如今,获得屏幕阅读器非常容易。 Android 手机上预装了TalkBack,iOS 和 macOS 上预装了VoiceOver,Windows 上预装了Narrator。
要使用更常用的屏幕阅读器进行测试,NVDA 是免费选项。