简介
我正在制作一个密码输入框,它配有密码强度指示器和密码标准列表。为了实现无障碍,期望的流程如下:
- 用户聚焦到密码输入框,并且屏幕阅读器读出密码标准;
- 当用户输入时,密码强度改善将被宣布(无效 -> 差 -> 好 -> 强)。
代码
HTML和JS的简化版本如下:
const passwordInput = document.getElementById('password');
const strengthValue = document.getElementById('strength');
passwordInput.addEventListener('input', (e) => {
const index = e.target.value.length < 3 ? e.target.value.length : 3
const strength = ['invalid', 'poor', 'good', 'strong'][index]
strengthValue.innerHTML = `Password strength is ${strength}`
});
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="criteria" />
<p id="strength" aria-live="polite">Password strength is invalid</p>
<p id="criteria">Your password must contain both upper and lowercase letters</p>
这也可以在这个Codepen中看到。
问题
上面的代码结果如下:
- 用户聚焦于密码输入,然后宣布了标准;
- 用户输入一个字符,强度变化被宣布,然后再次宣布标准;
- 进一步的输入导致强度公告但不是标准。
问题出在第2步。标准不应该重复。其他都没问题。
评论
- 这是在MacOS上使用Chrome、Firefox、Safari和Edge时发生的。
- 这仅发生在输入的第一个字符上。如果等到输入两个字符时才宣布强度,则标准不会重复。
- 我在React中遇到了这个问题,并将其简化为HTML/Vanilla JS进行调试,我的理由是如果在HTML/Vanilla JS中发生这种情况,那么React的增加复杂性只会让事情更加混乱。如果在React中看到它有帮助,这里是一个CodeSandbox。
- 我有一个解决方法,即在检测到密码输入的
value时删除id="criteria"节点的id。这有效,但感觉应该有更好的解决方案。
如果有人能够说明为什么会发生这种情况以及是否存在优雅/适当的解决方案,我会非常感兴趣了解更多。我没有成功地找到有关aria-live和aria-describedby节点如何一起使用的更多技术解释,所以我遇到了一些困难。提前致谢。