使用React state触发aria-live区域时Firefox+VoiceOver无播报问题
React 中 aria-live 属性在 Firefox + VoiceOver 环境下不生效问题解决
问题说明
- 异常仅出现在 Firefox 浏览器搭配 Mac 端 VoiceOver 屏幕阅读器的环境下
- 给
p标签添加aria-live属性后,动态更新标签内容时,VoiceOver 不会播报更新后的文本 - 相同逻辑用原生 HTML + JS 实现运行正常
- 如果使用Mac设备且此前未使用过VoiceOver,可按住Command键连按三次TouchID启动该屏幕阅读器进行测试
原因分析
React 更新动态文本时默认复用现有文本节点,仅修改节点的文本内容。Firefox 浏览器的 VoiceOver 对 aria-live 区域的监听逻辑要求节点发生新增/销毁/完整内容替换操作才会触发播报,直接修改文本节点值无法触发监听。
解决方案
推荐最简单的兼容方案:给 aria-live 绑定的节点添加和动态内容绑定的key属性,触发 React 每次更新时重建节点,即可触发屏幕阅读器播报:
// 修改后的对应代码 <p aria-live="polite" key={text}>{text}</p>
其他可选兼容方案:
- 给 aria-live 节点添加
aria-atomic="true"属性,强制屏幕阅读器每次读取区域完整内容:<p aria-live="polite" aria-atomic="true">{text}</p> - 每次更新内容前先将节点内容置空,再赋值为目标内容,模拟原生 JS 的内容替换逻辑
复现代码参考
异常的React实现代码
const App = () => { const [text, setText] = React.useState('hello') const handleClick = () => { if(text === 'hello') { setText('goodbye') } else { setText('hello') } } return ( <div> <p aria-live="polite">{text}</p> <button type="button" onClick={handleClick} > click </button> </div> ) } ReactDOM.render(<App />, document.getElementById("root"))
<!-- 对应HTML --> <div id="root"></div>
正常运行的原生HTML/JS实现代码
<div> <p aria-live="polite" id="text">hello</p> <button type="button" id="btn" > click here </button> </div> <script> const text = document.getElementById('text'); const btn = document.getElementById('btn'); function handleClick() { if (text.innerText === 'hello') { text.innerText = 'goodbye'; } else { text.innerText = 'hello'; } } btn.addEventListener('click', handleClick); </script>
内容的提问来源于stack exchange,提问作者Jake Loew
相关产品推荐
相关产品推荐

